Skip to content

mamut_routing_lib.td.models

Pydantic models for time-dependent (TDVRPTW / TDVRP) benchmark instances.

TD instances have no static arc_costs matrix: travel is described by per-arc arrival-time functions (ATFs) shipped in a sidecar file referenced by the td block. The TDVRPTW variant carries service times and time windows; the TDVRP variant keeps service times but has no time windows. Both share the same ATF sidecar content.

TD_ATF_MODEL module-attribute

TD_ATF_MODEL = 'atf-ndcpwlf'

TD_IGP_MODEL module-attribute

TD_IGP_MODEL = 'igp-profile'

TD_ROAD_MODEL module-attribute

TD_ROAD_MODEL = 'road-graph'

ATF_FORMAT module-attribute

ATF_FORMAT = 'mamut-td-atf'

ATF_FORMAT_VERSION module-attribute

ATF_FORMAT_VERSION = 1

IGP_CATEGORIES_FORMAT module-attribute

IGP_CATEGORIES_FORMAT = 'mamut-td-igp-categories'

IGP_CATEGORIES_FORMAT_VERSION module-attribute

IGP_CATEGORIES_FORMAT_VERSION = 1

ROAD_GRAPH_FORMAT module-attribute

ROAD_GRAPH_FORMAT = 'mamut-road-graph'

ROAD_GRAPH_FORMAT_VERSION module-attribute

ROAD_GRAPH_FORMAT_VERSION = 2

TRAFFIC_OVERLAY_FORMAT module-attribute

TRAFFIC_OVERLAY_FORMAT = 'mamut-traffic-overlay'

TRAFFIC_OVERLAY_FORMAT_VERSION module-attribute

TRAFFIC_OVERLAY_FORMAT_VERSION = 1

AnyTDTravelModelRef module-attribute

AnyTDTravelModelRef = Annotated[TDArrivalFunctionsRef | TDIGPProfileRef | TDRoadGraphRef, Field(discriminator='model')]

AnyTDBenchmarkInstance module-attribute

AnyTDBenchmarkInstance = BenchmarkInstanceTDVRPTW | BenchmarkInstanceTDVRP

TDArrivalFunctionsRef

Bases: BaseModel

Reference to the ATF sidecar file of a TD instance.

atf_path is relative to the directory containing the instance file. atf_sha256 is computed over the uncompressed canonical JSON bytes of the sidecar, so it is stable across .json and .json.gz storage.

model class-attribute instance-attribute

model: Literal['atf-ndcpwlf'] = TD_ATF_MODEL

atf_path instance-attribute

atf_path: str

atf_sha256 class-attribute instance-attribute

atf_sha256: str | None = None

validate_atf_path classmethod

validate_atf_path(value: str) -> str
Source code in MAMUT-routing-tools/MAMUT-routing-lib/src/mamut_routing_lib/td/models.py
@field_validator("atf_path")
@classmethod
def validate_atf_path(cls, value: str) -> str:
    return _validate_sidecar_path(value, "atf_path")

TDIGPProfileRef

Bases: BaseModel

Compact IGP (Ichoua-Gendreau-Potvin 2003) time-dependent travel model.

Instead of shipping a consolidated ATF sidecar, the instance stores the IGP data that fully determines it: contiguous time_periods (stored absolute floats are canonical — never recomputed), a strictly positive speeds matrix (num_categories x num_periods; FIFO by construction), and a reference to the arc-category sidecar. The canonical ATFs are materialized deterministically on load (mamut_routing_lib.td.igp); atf_sha256 pins the materialized canonical ATF bytes exactly as it would for a committed sidecar. See the TD benchmark standard and the Lera2026 family design note.

model class-attribute instance-attribute

model: Literal['igp-profile'] = TD_IGP_MODEL

time_periods instance-attribute

time_periods: list[tuple[float, float]]

speeds instance-attribute

speeds: list[list[float]]

categories_path instance-attribute

categories_path: str

categories_sha256 class-attribute instance-attribute

categories_sha256: str | None = None

atf_sha256 class-attribute instance-attribute

atf_sha256: str | None = None

validate_categories_path classmethod

validate_categories_path(value: str) -> str
Source code in MAMUT-routing-tools/MAMUT-routing-lib/src/mamut_routing_lib/td/models.py
@field_validator("categories_path")
@classmethod
def validate_categories_path(cls, value: str) -> str:
    return _validate_sidecar_path(value, "categories_path")

validate_time_periods classmethod

validate_time_periods(value: list[tuple[float, float]]) -> list[tuple[float, float]]
Source code in MAMUT-routing-tools/MAMUT-routing-lib/src/mamut_routing_lib/td/models.py
@field_validator("time_periods")
@classmethod
def validate_time_periods(cls, value: list[tuple[float, float]]) -> list[tuple[float, float]]:
    if not value:
        raise ValueError("time_periods must be non-empty")
    for index, (start, end) in enumerate(value):
        if start >= end:
            raise ValueError(f"time period {index} is empty or reversed: [{start}, {end}]")
        if index > 0 and value[index - 1][1] != start:
            raise ValueError(
                f"time periods must be contiguous: period {index} starts at {start}, "
                f"previous ends at {value[index - 1][1]}"
            )
    return value

validate_speeds classmethod

validate_speeds(value: list[list[float]], info: Any) -> list[list[float]]
Source code in MAMUT-routing-tools/MAMUT-routing-lib/src/mamut_routing_lib/td/models.py
@field_validator("speeds")
@classmethod
def validate_speeds(cls, value: list[list[float]], info: Any) -> list[list[float]]:
    if not value:
        raise ValueError("speeds must have at least one category row")
    num_periods = len(info.data.get("time_periods", []))
    for c, row in enumerate(value):
        if num_periods and len(row) != num_periods:
            raise ValueError(
                f"speeds row {c} has {len(row)} entries, expected one per time period ({num_periods})"
            )
        for p, speed in enumerate(row):
            if speed <= 0:
                raise ValueError(f"speeds[{c}][{p}] = {speed} must be strictly positive (FIFO)")
    return value

num_categories

num_categories() -> int
Source code in MAMUT-routing-tools/MAMUT-routing-lib/src/mamut_routing_lib/td/models.py
def num_categories(self) -> int:
    return len(self.speeds)

TDRoadGraphRef

Bases: BaseModel

Compact road-network time-dependent travel model (format v2).

The instance references two sidecars, both collection-root-relative and sha-pinned: the static road graph shared by every traffic subinstance of the base (<base>.road.json.gz: trimmed subgraph with per-edge free-flow speed_limit and vertex coordinates) and one traffic overlay (<base>.traffic-<model>-<intensity>.json.gz: per-edge 24-bin speeds aligned with the graph's edge order, clamped at free-flow). The canonical ATFs are materialized deterministically on load (mamut_routing_lib.td.roadgraph): pinned Dijkstra over the static free-flow times, exact per-edge arrival functions from the overlay speeds sampled exactly along the pinned paths on a fixed departure grid, then deterministic decimation. sample_step and simplify_tolerance are the authoritative materialization parameters and must equal the values recorded in the road sidecar. atf_sha256 pins the materialized canonical ATF bytes exactly as it would for a committed sidecar. See the TD benchmark standard (road-graph v2).

model class-attribute instance-attribute

model: Literal['road-graph'] = TD_ROAD_MODEL

graph instance-attribute

graph: SidecarRef

traffic instance-attribute

traffic: SidecarRef

atf_sha256 class-attribute instance-attribute

atf_sha256: str | None = None

sample_step instance-attribute

sample_step: float

simplify_tolerance instance-attribute

simplify_tolerance: float

validate_sample_step classmethod

validate_sample_step(value: float) -> float
Source code in MAMUT-routing-tools/MAMUT-routing-lib/src/mamut_routing_lib/td/models.py
@field_validator("sample_step")
@classmethod
def validate_sample_step(cls, value: float) -> float:
    if value <= 0:
        raise ValueError(f"sample_step must be strictly positive, got {value}")
    return value

validate_simplify_tolerance classmethod

validate_simplify_tolerance(value: float) -> float
Source code in MAMUT-routing-tools/MAMUT-routing-lib/src/mamut_routing_lib/td/models.py
@field_validator("simplify_tolerance")
@classmethod
def validate_simplify_tolerance(cls, value: float) -> float:
    if value < 0:
        raise ValueError(f"simplify_tolerance must be >= 0, got {value}")
    return value

BenchmarkInstanceTDVRPTW

Bases: _TDInstanceValidationMixin

time_windows instance-attribute

time_windows: list[tuple[int | float, int | float]]

validate_time_window_lengths classmethod

validate_time_window_lengths(value: list[Any], info: Any) -> list[Any]
Source code in MAMUT-routing-tools/MAMUT-routing-lib/src/mamut_routing_lib/td/models.py
@field_validator("time_windows")
@classmethod
def validate_time_window_lengths(cls, value: list[Any], info: Any) -> list[Any]:
    expected_length = info.data["num_customers"] + 1
    if len(value) != expected_length:
        raise ValueError(
            f"Length of time_windows must be {expected_length} "
            f"(based on num_customers={info.data['num_customers']} + 1 for depot)"
        )
    for index, (earliest, latest) in enumerate(value):
        if earliest > latest:
            raise ValueError(f"time window at index {index} has earliest > latest")
    return value

BenchmarkInstanceTDVRP

Bases: _TDInstanceValidationMixin