Source code for discrete_optimization.tsp.solvers.cp_mzn

#  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 logging
import os
from typing import Any, Optional

from minizinc import Instance, Model, Solver

from discrete_optimization.generic_tools.cp_tools import (
    CpSolverName,
    MinizincCpSolver,
    find_right_minizinc_solver_name,
)
from discrete_optimization.generic_tools.do_problem import ParamsObjectiveFunction
from discrete_optimization.tsp.problem import TspProblem, TspSolution
from discrete_optimization.tsp.solvers import TspSolver
from discrete_optimization.tsp.utils import build_matrice_distance

logger = logging.getLogger(__name__)
this_path = os.path.dirname(os.path.abspath(__file__))


[docs] class CPTspModel: FLOAT_VERSION = 0 INT_VERSION = 1
[docs] class CpTspSolver(MinizincCpSolver, TspSolver): def __init__( self, problem: TspProblem, model_type: CPTspModel, cp_solver_name: CpSolverName = CpSolverName.CHUFFED, params_objective_function: Optional[ParamsObjectiveFunction] = None, silent_solve_error: bool = False, **kwargs ): super().__init__( problem=problem, params_objective_function=params_objective_function ) self.silent_solve_error = silent_solve_error self.model_type = model_type self.start_index = self.problem.start_index self.end_index = self.problem.end_index self.cp_solver_name = cp_solver_name self.key_decision_variable = ["x"] self.distance_matrix = build_matrice_distance( self.problem.node_count, method=self.problem.evaluate_function_indexes, ) self.distance_matrix[self.end_index, self.start_index] = 0 self.distance_list_2d = [ [ int(x) if model_type == CPTspModel.INT_VERSION else x for x in self.distance_matrix[i, :] ] for i in range(self.distance_matrix.shape[0]) ]
[docs] def init_model(self, **args: Any) -> None: if self.model_type == CPTspModel.FLOAT_VERSION: model = Model(os.path.join(this_path, "../minizinc/tsp_float.mzn")) if self.model_type == CPTspModel.INT_VERSION: model = Model(os.path.join(this_path, "../minizinc/tsp_int.mzn")) # Find the MiniZinc solver configuration for Gecode solver = Solver.lookup(find_right_minizinc_solver_name(self.cp_solver_name)) # Create an Instance of the n-Queens model for Gecode instance = Instance(solver, model) instance["n"] = self.problem.node_count instance["distances"] = self.distance_list_2d instance["start"] = self.start_index + 1 instance["end"] = self.end_index + 1 self.instance = instance
[docs] def retrieve_solution( self, _output_item: Optional[str] = None, **kwargs: Any ) -> TspSolution: """Return a d-o solution from the variables computed by minizinc. Args: _output_item: string representing the minizinc solver output passed by minizinc to the solution constructor **kwargs: keyword arguments passed by minzinc to the solution contructor containing the objective value (key "objective"), and the computed variables as defined in minizinc model. Returns: """ circuit = kwargs["x"] return self._retrieve_solution_from_circuit(circuit)
def _retrieve_solution_from_circuit(self, circuit: list[int]) -> TspSolution: path = [] cur_pos = self.start_index init = False while cur_pos != self.end_index or not init: next_pos = circuit[cur_pos] - 1 path += [next_pos] cur_pos = next_pos init = True return TspSolution( problem=self.problem, start_index=self.start_index, end_index=self.end_index, permutation=path[:-1], length=None, lengths=None, )