Spaces:
Sleeping
Sleeping
| from typing import List | |
| from datetime import datetime, timedelta | |
| from . import domain | |
| # Conversion functions from domain to API models | |
| def location_to_model(location: domain.Location) -> List[float]: | |
| return [location.latitude, location.longitude] | |
| def visit_to_model(visit: domain.Visit) -> domain.VisitModel: | |
| return domain.VisitModel( | |
| id=visit.id, | |
| name=visit.name, | |
| location=location_to_model(visit.location), | |
| demand=visit.demand, | |
| min_start_time=visit.min_start_time.isoformat(), | |
| max_end_time=visit.max_end_time.isoformat(), | |
| service_duration=int(visit.service_duration.total_seconds()), | |
| vehicle=visit.vehicle.id if visit.vehicle else None, | |
| previous_visit=visit.previous_visit.id if visit.previous_visit else None, | |
| next_visit=visit.next_visit.id if visit.next_visit else None, | |
| arrival_time=visit.arrival_time.isoformat() if visit.arrival_time else None, | |
| start_service_time=visit.start_service_time.isoformat() | |
| if visit.start_service_time | |
| else None, | |
| departure_time=visit.departure_time.isoformat() | |
| if visit.departure_time | |
| else None, | |
| driving_time_seconds_from_previous_standstill=visit.driving_time_seconds_from_previous_standstill, | |
| ) | |
| def vehicle_to_model(vehicle: domain.Vehicle) -> domain.VehicleModel: | |
| return domain.VehicleModel( | |
| id=vehicle.id, | |
| name=vehicle.name, | |
| capacity=vehicle.capacity, | |
| home_location=location_to_model(vehicle.home_location), | |
| departure_time=vehicle.departure_time.isoformat(), | |
| visits=[visit.id for visit in vehicle.visits], | |
| total_demand=vehicle.total_demand, | |
| total_driving_time_seconds=vehicle.total_driving_time_seconds, | |
| arrival_time=vehicle.arrival_time.isoformat(), | |
| ) | |
| def plan_to_model(plan: domain.VehicleRoutePlan) -> domain.VehicleRoutePlanModel: | |
| return domain.VehicleRoutePlanModel( | |
| name=plan.name, | |
| south_west_corner=location_to_model(plan.south_west_corner), | |
| north_east_corner=location_to_model(plan.north_east_corner), | |
| vehicles=[vehicle_to_model(v) for v in plan.vehicles], | |
| visits=[visit_to_model(v) for v in plan.visits], | |
| score=str(plan.score) if plan.score else None, | |
| solver_status=plan.solver_status.name if plan.solver_status else None, | |
| total_driving_time_seconds=plan.total_driving_time_seconds, | |
| start_date_time=plan.start_date_time.isoformat() | |
| if plan.start_date_time | |
| else None, | |
| end_date_time=plan.end_date_time.isoformat() if plan.end_date_time else None, | |
| ) | |
| # Conversion functions from API models to domain | |
| def model_to_location(model: List[float]) -> domain.Location: | |
| return domain.Location(latitude=model[0], longitude=model[1]) | |
| def model_to_visit( | |
| model: domain.VisitModel, vehicle_lookup: dict, visit_lookup: dict | |
| ) -> domain.Visit: | |
| # Handle vehicle reference | |
| vehicle = None | |
| if model.vehicle: | |
| if isinstance(model.vehicle, str): | |
| vehicle = vehicle_lookup[model.vehicle] | |
| else: | |
| # This shouldn't happen in practice, but handle it for completeness | |
| vehicle = vehicle_lookup[model.vehicle.id] | |
| # Handle previous visit reference | |
| previous_visit = None | |
| if model.previous_visit: | |
| if isinstance(model.previous_visit, str): | |
| previous_visit = visit_lookup[model.previous_visit] | |
| else: | |
| previous_visit = visit_lookup[model.previous_visit.id] | |
| # Handle next visit reference | |
| next_visit = None | |
| if model.next_visit: | |
| if isinstance(model.next_visit, str): | |
| next_visit = visit_lookup[model.next_visit] | |
| else: | |
| next_visit = visit_lookup[model.next_visit.id] | |
| return domain.Visit( | |
| id=model.id, | |
| name=model.name, | |
| location=model_to_location(model.location), | |
| demand=model.demand, | |
| min_start_time=datetime.fromisoformat(model.min_start_time), | |
| max_end_time=datetime.fromisoformat(model.max_end_time), | |
| service_duration=timedelta(seconds=model.service_duration), | |
| vehicle=vehicle, | |
| previous_visit=previous_visit, | |
| next_visit=next_visit, | |
| arrival_time=datetime.fromisoformat(model.arrival_time) | |
| if model.arrival_time | |
| else None, | |
| ) | |
| def model_to_vehicle(model: domain.VehicleModel, visit_lookup: dict) -> domain.Vehicle: | |
| # Handle visits references | |
| visits = [] | |
| for visit_ref in model.visits: | |
| if isinstance(visit_ref, str): | |
| visits.append(visit_lookup[visit_ref]) | |
| else: | |
| visits.append(visit_lookup[visit_ref.id]) | |
| return domain.Vehicle( | |
| id=model.id, | |
| capacity=model.capacity, | |
| home_location=model_to_location(model.home_location), | |
| departure_time=datetime.fromisoformat(model.departure_time), | |
| visits=visits, | |
| ) | |
| def model_to_plan(model: domain.VehicleRoutePlanModel) -> domain.VehicleRoutePlan: | |
| # Convert basic collections first | |
| vehicles = [] | |
| visits = [] | |
| # Convert visits first (they don't depend on vehicles) | |
| for visit_model in model.visits: | |
| visit = domain.Visit( | |
| id=visit_model.id, | |
| name=visit_model.name, | |
| location=model_to_location(visit_model.location), | |
| demand=visit_model.demand, | |
| min_start_time=datetime.fromisoformat(visit_model.min_start_time), | |
| max_end_time=datetime.fromisoformat(visit_model.max_end_time), | |
| service_duration=timedelta(seconds=visit_model.service_duration), | |
| vehicle=None, # Will be set later | |
| previous_visit=None, # Will be set later | |
| next_visit=None, # Will be set later | |
| arrival_time=datetime.fromisoformat(visit_model.arrival_time) | |
| if visit_model.arrival_time | |
| else None, | |
| ) | |
| visits.append(visit) | |
| # Create lookup dictionaries | |
| visit_lookup = {v.id: v for v in visits} | |
| # Convert vehicles | |
| for vehicle_model in model.vehicles: | |
| vehicle = domain.Vehicle( | |
| id=vehicle_model.id, | |
| name=vehicle_model.name, | |
| capacity=vehicle_model.capacity, | |
| home_location=model_to_location(vehicle_model.home_location), | |
| departure_time=datetime.fromisoformat(vehicle_model.departure_time), | |
| visits=[], | |
| ) | |
| vehicles.append(vehicle) | |
| # Create vehicle lookup | |
| vehicle_lookup = {v.id: v for v in vehicles} | |
| # Now set up the relationships | |
| for i, visit_model in enumerate(model.visits): | |
| visit = visits[i] | |
| # Set vehicle reference | |
| if visit_model.vehicle: | |
| if isinstance(visit_model.vehicle, str): | |
| visit.vehicle = vehicle_lookup[visit_model.vehicle] | |
| else: | |
| visit.vehicle = vehicle_lookup[visit_model.vehicle.id] | |
| # Set previous/next visit references | |
| if visit_model.previous_visit: | |
| if isinstance(visit_model.previous_visit, str): | |
| visit.previous_visit = visit_lookup[visit_model.previous_visit] | |
| else: | |
| visit.previous_visit = visit_lookup[visit_model.previous_visit.id] | |
| if visit_model.next_visit: | |
| if isinstance(visit_model.next_visit, str): | |
| visit.next_visit = visit_lookup[visit_model.next_visit] | |
| else: | |
| visit.next_visit = visit_lookup[visit_model.next_visit.id] | |
| # Set up vehicle visits lists | |
| for vehicle_model in model.vehicles: | |
| vehicle = vehicle_lookup[vehicle_model.id] | |
| for visit_ref in vehicle_model.visits: | |
| if isinstance(visit_ref, str): | |
| vehicle.visits.append(visit_lookup[visit_ref]) | |
| else: | |
| vehicle.visits.append(visit_lookup[visit_ref.id]) | |
| # Handle score | |
| score = None | |
| if model.score: | |
| from solverforge_legacy.solver.score import HardSoftScore | |
| score = HardSoftScore.parse(model.score) | |
| # Handle solver status | |
| solver_status = domain.SolverStatus.NOT_SOLVING | |
| if model.solver_status: | |
| solver_status = domain.SolverStatus[model.solver_status] | |
| return domain.VehicleRoutePlan( | |
| name=model.name, | |
| south_west_corner=model_to_location(model.south_west_corner), | |
| north_east_corner=model_to_location(model.north_east_corner), | |
| vehicles=vehicles, | |
| visits=visits, | |
| score=score, | |
| solver_status=solver_status, | |
| ) | |