Source code for discrete_optimization.vrptw.solvers.ortools_routing

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

from ortools.constraint_solver import routing_enums_pb2

from discrete_optimization.generic_tools.callbacks.callback import (
    Callback,
    CallbackList,
)
from discrete_optimization.generic_tools.do_solver import SolverDO
from discrete_optimization.generic_tools.result_storage.result_storage import (
    ResultStorage,
)
from discrete_optimization.gpdp.problem import GpdpProblem, GpdpSolution, ProxyClass
from discrete_optimization.gpdp.solvers import GpdpSolver
from discrete_optimization.gpdp.solvers.ortools_routing import (
    OrtoolsGpdpSolver,
    ParametersCost,
)
from discrete_optimization.vrptw.problem import VRPTWProblem, VRPTWSolution


[docs] class OrtoolsVrpTwSolver(SolverDO): problem: VRPTWProblem gpdp_problem: GpdpProblem solver: OrtoolsGpdpSolver
[docs] def init_model( self, time_limit=10, scaling: float = 100, cost_per_vehicle: int = 100000, **kwargs: Any, ) -> None: gpdp_problem = ProxyClass.from_vrptw_to_gpdp(self.problem, True) solver = OrtoolsGpdpSolver(problem=gpdp_problem, factor_multiplier_time=scaling) solver.init_model( one_visit_per_node=True, include_time_windows=True, include_demand=True, neg_capacity_version=False, include_time_dimension=True, consider_empty_route_cost=False, cost_per_vehicle_used=cost_per_vehicle, local_search_metaheuristic=routing_enums_pb2.LocalSearchMetaheuristic.SIMULATED_ANNEALING, first_solution_strategy=routing_enums_pb2.FirstSolutionStrategy.AUTOMATIC, time_limit=time_limit, parameters_cost=[ ParametersCost( dimension_name="Time", global_span=False, coefficient_vehicles=[1] * gpdp_problem.number_vehicle, ) ], ) self.solver = solver
[docs] def solve( self, callbacks: Optional[list[Callback]] = None, **kwargs: Any ) -> ResultStorage: callback = CallbackList(callbacks) callback.on_solve_start(self) result_storage = self.create_result_storage([]) res = self.solver.solve() sol: GpdpSolution = res[-1][0] vrp_tw_sol = VRPTWSolution( problem=self.problem, routes=[ [x + 1 for x in sol.trajectories[i][1:-1]] for i in range(len(sol.trajectories)) ], ) vrp_tw_sol.routes = [r for r in vrp_tw_sol.routes if len(r) > 1] print(vrp_tw_sol.routes) fit = self.aggreg_from_sol(vrp_tw_sol) result_storage.append((vrp_tw_sol, fit)) callback.on_solve_end(result_storage, self) return result_storage