Source code for discrete_optimization.knapsack.solvers.lns_cp

#  Copyright (c) 2022 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.

import random
from collections.abc import Iterable
from typing import Any, Optional

from minizinc import Instance
from ortools.sat.python.cp_model import Constraint

from discrete_optimization.generic_tools.cp_tools import MinizincCpSolver
from discrete_optimization.generic_tools.do_solver import SolverDO
from discrete_optimization.generic_tools.hyperparameters.hyperparameter import (
    FloatHyperparameter,
)
from discrete_optimization.generic_tools.lns_cp import (
    MznConstraintHandler,
    OrtoolsCpSatConstraintHandler,
)
from discrete_optimization.generic_tools.ortools_cpsat_tools import OrtoolsCpSatSolver
from discrete_optimization.knapsack.problem import KnapsackProblem, KnapsackSolution
from discrete_optimization.knapsack.solvers.cp_mzn import Cp2KnapsackSolver
from discrete_optimization.knapsack.solvers.cpsat import CpSatKnapsackSolver
from discrete_optimization.knapsack.solvers.greedy import ResultStorage


[docs] class KnapsackMznConstraintHandler(MznConstraintHandler): hyperparameters = [ FloatHyperparameter(name="fraction_to_fix", default=0.9, low=0.0, high=1.0), ] def __init__(self, problem: KnapsackProblem, fraction_to_fix: float = 0.9): self.problem = problem self.fraction_to_fix = fraction_to_fix self.iter = 0
[docs] def adding_constraint_from_results_store( self, solver: MinizincCpSolver, result_storage: ResultStorage, result_storage_last_iteration: ResultStorage, child_instance: Instance, **kwargs: Any, ) -> Iterable[Any]: """Add constraints to the internal model of a solver based on previous solutions Args: solver: solver whose internal model is updated result_storage: all results so far result_storage_last_iteration: results from last LNS iteration only child_instance: minizinc instance where to include the constraints **kwargs: Returns: empty list, not used """ if not isinstance(solver, Cp2KnapsackSolver): raise ValueError("cp_solver must a CPKnapsackMZN2 for this constraint.") subpart_item = set( random.sample( range(self.problem.nb_items), int(self.fraction_to_fix * self.problem.nb_items), ) ) current_solution = self.extract_best_solution_from_last_iteration( result_storage=result_storage, result_storage_last_iteration=result_storage_last_iteration, ) if not isinstance(current_solution, KnapsackSolution): raise ValueError( "result_storage.get_best_solution() should be a KnapsackSolution." ) list_strings = [] for item in subpart_item: list_strings += [ "constraint taken[" + str(item + 1) + "] == " + str(current_solution.list_taken[item]) + ";\n" ] child_instance.add_string(list_strings[-1]) return list_strings
[docs] class OrtoolsCpSatKnapsackConstraintHandler(OrtoolsCpSatConstraintHandler): hyperparameters = [ FloatHyperparameter(name="fraction_to_fix", default=0.9, low=0.0, high=1.0), ] def __init__(self, problem: KnapsackProblem, fraction_to_fix: float = 0.9): self.problem = problem self.fraction_to_fix = fraction_to_fix self.iter = 0
[docs] def adding_constraint_from_results_store( self, solver: OrtoolsCpSatSolver, result_storage: ResultStorage, result_storage_last_iteration: ResultStorage, **kwargs: Any, ) -> Iterable[Constraint]: """Add constraints to the internal model of a solver based on previous solutions Args: solver: solver whose internal model is updated result_storage: all results so far result_storage_last_iteration: results from last LNS iteration only **kwargs: Returns: list of added constraints """ if not isinstance(solver, CpSatKnapsackSolver): raise ValueError( "cp_solver must a CpSatKnapsackSolver for this constraint." ) lns_constraints = [] subpart_item = set( random.sample( range(self.problem.nb_items), int(self.fraction_to_fix * self.problem.nb_items), ) ) current_solution = self.extract_best_solution_from_last_iteration( result_storage=result_storage, result_storage_last_iteration=result_storage_last_iteration, ) if current_solution is None: raise ValueError("result_storage.get_best_solution() should not be None.") if not isinstance(current_solution, KnapsackSolution): raise ValueError( "result_storage.get_best_solution() should be a KnapsackSolution." ) variables = solver.variables["taken"] for item in subpart_item: lns_constraints.append( solver.cp_model.Add( variables[item] == current_solution.list_taken[item] ) ) return lns_constraints