Source code for discrete_optimization.gpdp.transformations.from_vrptw

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

"""Transformation from VRPTW to GPDP (General Pickup and Delivery Problem)."""

from typing import Optional

from discrete_optimization.generic_tools.transformation.problem_transformation import (
    ProblemTransformation,
)
from discrete_optimization.generic_tools.transformation.transformation_metadata import (
    TransformationMetadata,
    exact_transformation,
)
from discrete_optimization.gpdp.problem import GpdpProblem, GpdpSolution
from discrete_optimization.vrptw.problem import VRPTWProblem, VRPTWSolution


[docs] class VrptwToGpdpTransformation( ProblemTransformation[VRPTWProblem, VRPTWSolution, GpdpProblem, GpdpSolution] ): """Transform VRPTW to GPDP. VRPTW is a special case of GPDP with time windows and demand constraints. """ def __init__(self, compute_graph: bool = False): self.compute_graph = compute_graph
[docs] def get_forward_metadata(self) -> TransformationMetadata: return exact_transformation( use_cases=[ "Use GPDP solvers for VRPTW problems", "VRPTW constraints preserved in GPDP", ] )
[docs] def transform_problem(self, source_problem: VRPTWProblem) -> GpdpProblem: """Transform VRPTW to GPDP using the existing ProxyClass implementation.""" from discrete_optimization.gpdp.problem import ProxyClass return ProxyClass.from_vrptw_to_gpdp( source_problem, compute_graph=self.compute_graph )
[docs] def back_transform_solution( self, solution: GpdpSolution, source_problem: VRPTWProblem ) -> VRPTWSolution: """Transform GPDP solution back to VRPTW solution.""" routes = [] for v in range(source_problem.nb_vehicles): if v in solution.trajectories: # Filter depot nodes from trajectory route = [ node for node in solution.trajectories[v] if node != source_problem.depot_node ] routes.append(route) else: routes.append([]) return VRPTWSolution(problem=source_problem, routes=routes)
[docs] def forward_transform_solution( self, solution: VRPTWSolution, target_problem: GpdpProblem ) -> Optional[GpdpSolution]: """Transform VRPTW solution to GPDP solution.""" trajectories = {} for v, route in enumerate(solution.routes): trajectories[v] = ( [target_problem.origin_vehicle[v]] + list(route) + [target_problem.target_vehicle[v]] ) # Compute times times = {} for v, traj in trajectories.items(): current_time = 0.0 for i, node in enumerate(traj): times[node] = current_time if i < len(traj) - 1: next_node = traj[i + 1] current_time += target_problem.time_delta[node][next_node] return GpdpSolution( problem=target_problem, trajectories=trajectories, times=times, resource_evolution={}, )