Source code for discrete_optimization.binpack.solvers.toulbar

#  Copyright (c) 2025 AIRBUS and its affiliates.
#  This source code is licensed under the MIT license found in the
#  LICENSE file in the root directory of this source tree.
try:
    import pytoulbar2
except ImportError:
    toulbar_available = False
else:
    toulbar_available = True
from discrete_optimization.binpack.problem import BinPackProblem, BinPackSolution
from discrete_optimization.generic_tools.do_solver import WarmstartMixin
from discrete_optimization.generic_tools.toulbar_tools import ToulbarSolver


[docs] class ToulbarBinPackSolver(ToulbarSolver, WarmstartMixin): problem: BinPackProblem
[docs] def init_model(self, **kwargs) -> None: kwargs = self.complete_with_default_hyperparameters(kwargs) number_items = self.problem.nb_items neighs_dict = {} for i in range(number_items): edges = [ x for x in self.problem.incompatible_items if x[0] == i or x[1] == i ] neighs = [x[0] if x[0] != i else x[1] for x in edges] neighs_dict[i] = neighs # we don't have to have a very tight bound. model = pytoulbar2.CFN(number_items, vns=kwargs["vns"]) model.AddVariable("nb_bins", range(number_items)) model.AddFunction(["nb_bins"], range(number_items)) for i in range(number_items): model.AddVariable(f"x_{i}", range(i + 1)) model.AddLinearConstraint([1, -1], [f"x_{i}", "nb_bins"], "<=", 0) # encode that x_{i}<=nb_bins. for i in range(number_items): neighs = neighs_dict[i] if len(neighs) > 0: for neigh in neighs: model.AddFunction( [f"x_{i}", f"x_{neigh}"], [ 1000 if i == j else 0 for i in range(i + 1) for j in range(neigh + 1) ], ) for i in range(number_items): model.AddGeneralizedLinearConstraint( [ (f"x_{j}", i, self.problem.list_items[j].weight) for j in range(i, number_items) ], "<=", self.problem.capacity_bin, ) self.model = model if hasattr(self, "sol") and kwargs["greedy_start"]: self.set_warm_start(self.sol)
[docs] def retrieve_solution( self, solution_from_toulbar2: tuple[list, float, int] ) -> BinPackSolution: return BinPackSolution( problem=self.problem, allocation=solution_from_toulbar2[0][1 : 1 + self.problem.nb_items], )
[docs] def set_warm_start(self, solution: BinPackSolution) -> None: max_bin = max(solution.allocation) self.model.CFN.wcsp.setBestValue(0, max_bin) for i in range(1, self.problem.nb_items + 1): self.model.CFN.wcsp.setBestValue(i, solution.allocation[i - 1])