Source code for discrete_optimization.generic_tools.cp_tools

"""
Constraint programming common utilities and class that should be used by any solver using 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.

from __future__ import annotations

import logging
from abc import abstractmethod
from enum import Enum
from typing import Any, Optional

from discrete_optimization.generic_tools.callbacks.callback import (
    Callback,
)
from discrete_optimization.generic_tools.do_solver import SolverDO
from discrete_optimization.generic_tools.result_storage.result_storage import (
    ResultStorage,
)

logger = logging.getLogger(__name__)


[docs] class CpSolverName(Enum): """ Enum choice of underlying CP/LP solver used by Minizinc typically """ CHUFFED = 0 GECODE = 1 CPLEX = 2 CPOPT = 3 GUROBI = 4 ORTOOLS = 5 HIGHS = 6
map_cp_solver_name = { CpSolverName.CHUFFED: "chuffed", CpSolverName.GECODE: "gecode", CpSolverName.CPLEX: "cplex", CpSolverName.CPOPT: "cpo", # need to install https://github.com/IBMDecisionOptimization/cpofzn CpSolverName.GUROBI: "gurobi", CpSolverName.ORTOOLS: "ortools", CpSolverName.HIGHS: "highs", }
[docs] class ParametersCp: """ Parameters that can be used by any cp - solver """ intermediate_solution: bool free_search: bool multiprocess: bool nb_process: int optimisation_level: int def __init__( self, intermediate_solution: bool, free_search: bool = False, multiprocess: bool = False, nb_process: int = 1, optimisation_level: int = 1, ): """ :param intermediate_solution: retrieve intermediate solutions """ self.intermediate_solution = intermediate_solution self.free_search = free_search self.multiprocess = multiprocess self.nb_process = nb_process self.optimisation_level = optimisation_level
[docs] @staticmethod def default() -> "ParametersCp": return ParametersCp( intermediate_solution=True, free_search=False, optimisation_level=1, )
[docs] @staticmethod def default_cpsat() -> "ParametersCp": return ParametersCp( intermediate_solution=True, free_search=False, multiprocess=True, nb_process=6, optimisation_level=1, )
[docs] @staticmethod def default_fast_lns() -> "ParametersCp": return ParametersCp( intermediate_solution=True, free_search=False, )
[docs] @staticmethod def default_free() -> "ParametersCp": return ParametersCp( intermediate_solution=True, free_search=True, )
[docs] def copy(self) -> "ParametersCp": return ParametersCp( intermediate_solution=self.intermediate_solution, free_search=self.free_search, multiprocess=self.multiprocess, nb_process=self.nb_process, optimisation_level=self.optimisation_level, )
[docs] class SignEnum(Enum): EQUAL = "==" LEQ = "<=" UEQ = ">=" LESS = "<" UP = ">"
[docs] class CpSolver(SolverDO): """ Additional function to be implemented by a CP Solver. """
[docs] @abstractmethod def init_model(self, **args: Any) -> None: """ Instantiate a CP model instance Afterwards, self.instance should not be None anymore. """ ...
[docs] @abstractmethod def solve(
self, callbacks: Optional[list[Callback]] = None, parameters_cp: Optional[ParametersCp] = None, **args: Any, ) -> ResultStorage: ...
[docs] @abstractmethod def minimize_variable(self, var: Any) -> None: """Set the cp solver objective as minimizing `var`.""" pass
[docs] @abstractmethod def add_bound_constraint(self, var: Any, sign: SignEnum, value: int) -> list[Any]: """Add constraint of bound type on an integer variable (or expression) of the underlying cp model. `var` must compare to `value` according to `value`. Args: var: sign: value: Returns: """ ...