State Interface

The State Interface acts as an intermediary layer that manages the interaction between your application and the underlying storage systems. It abstracts the complexities of data storage, providing a simplified API for reading and writing state information.

The State Interface handles:

  • Reading: Populates the State from the Cached State

  • Writing: Computes differences and publishes changes to the Changes Stream

  • Abstraction: Hides storage complexity from your application

You can interact with the State Interface flexibly—adding, modifying, or removing entities as needed. The interface ensures that all changes are seamlessly persisted and managed behind the scenes.

Interface

The State is composed of two main parts: the Environment (input data) and the Solution (computed results).

        flowchart LR
   S[State] -->|environment| E[Environment]
   S -->|solution| Sol[Solution]

   style S fill:#4A90D9,color:#fff
   style E fill:#5BA55B,color:#fff
   style Sol fill:#D97B4A,color:#fff
    
class Entity

Enumeration of entity types for state management.

Variables:
  • STATE_MANAGER (str) – Represents the state manager entity.

  • SOLVER (str) – Represents the solver entity.

  • AGENT (str) – Represents the agent entity.

class State

Dora cached state implementation.

This class manages the state of the environment and solution for Dora, providing mechanisms for population, saving, and committing state changes. It ensures data integrity and seamless communication with the cache system. Freely modify the environment and solution attributes, create or delete entities, and call save() to persist all changes automatically.

Variables:
  • state_id (str) – The state ID to retrieve the cache for.

  • entity (Entity) – The entity type for the state.

  • state_cache_connection_url (str) – The state cache connection URL.

  • diffs_queue_connection_url (str) – The diffs queue connection URL.

  • metadata (Optional[StateDiff.StateUpdateMetadata]) – Metadata for the state.

  • environment (Environment) – The environment state containing vehicles, personnel, orders, and tags.

  • solution (Solution) – The solution state containing routes, stops, trips, and violations.

Example

>>> from pyutils.data_adapter.state.dora.base import State
>>> state = State(
...     state_id="state_123",
...     entity="SOLVER"
... )
>>> state.populate()
>>> # Modify the environment and solution as needed
>>> state.save()
async populate()

Populate the object with the data from the cache.

async save()

Save the current state to the cache with any changes made.

Environment

The Environment contains all input entities for the routing problem:

        flowchart TB
   E[Environment] -->|"fleet: Dict"| V[Vehicle]
   E -->|"personnel: Dict"| P[Personnel]
   E -->|"orders: Dict"| O[Order]
   E -->|"tags: Dict"| T[Tag]

   style E fill:#5BA55B,color:#fff
   style V fill:#7BC67B
   style P fill:#7BC67B
   style O fill:#7BC67B
   style T fill:#7BC67B
    
class Environment

Manages collections of vehicles, personnel, orders, and tags for a routing problem.

Provides helper methods to add and remove items from each collection.

Variables:
  • fleet (Dict[str, Vehicle]) – Dictionary mapping vehicle IDs to vehicle objects.

  • personnel (Dict[str, Personnel]) – Dictionary mapping personnel IDs to personnel objects.

  • orders (Dict[str, Order]) – Dictionary mapping order IDs to order objects.

  • tags (Dict[str, Tag]) – Dictionary mapping tag IDs to tag objects.

Example

>>> env = Environment()
>>> vehicle = Vehicle(id="vehicle_1",
...     type="VAN",
...     start_depot_id="depot_1",
...     end_depot_id="depot_1",
...     is_available=True,
...     start_time="08:00",
...     end_time="18:00",
...     capacity_kg=1000,
...     capacity_pallets=10,
...     max_trips=5,
...     max_working_time="10:00",
...     cost_per_km=0.5,
...     cost_per_minute=0.2,
...     tags={"AIRPORT", "REFRIGERATED"},
...     width_m=2.0,
...     length_m=5.0,
...     height_m=2.5)
>>> env.add_vehicle(vehicle)
>>> print(env.fleet) # {'vehicle_1': Vehicle(...)}
>>> env.remove_vehicle("vehicle_1")
>>> print(env.fleet) # {}
add_order(order)

Add an order to the environment.

Parameters:

order (Order) – The order to add.

add_personnel(personnel)

Add personnel to the environment.

Parameters:

personnel (Personnel) – The personnel to add.

add_tag(tag)

Add a tag to the environment.

Parameters:

tag (Tag) – The tag to add.

add_vehicle(vehicle)

Add a vehicle to the fleet.

Parameters:

vehicle (Vehicle) – The vehicle to add.

remove_order(order_id)

Remove an order from the environment.

Parameters:

order_id (str) – The ID of the order to remove.

remove_personnel(personnel_id)

Remove personnel from the environment.

Parameters:

personnel_id (str) – The ID of the personnel to remove.

remove_tag(tag_id)

Remove a tag from the environment.

Parameters:

tag_id (str) – The ID of the tag to remove.

remove_vehicle(vehicle_id)

Remove a vehicle from the fleet.

Parameters:

vehicle_id (str) – The ID of the vehicle to remove.

Fleet

class Vehicle

Represents a vehicle resource available for assignments in the environment.

Parameters:
  • id (str) – Unique identifier for the vehicle.

  • type (str) – Type of vehicle (e.g., BIGTRUCK, VAN).

  • start_depot_id (str) – Reference to the start depot node (node_id).

  • end_depot_id (str) – Reference to the end depot node (node_id).

  • is_available (bool) – Indicates if the vehicle is available for assignments.

  • unavailability_reason (Optional[str]) – Reason for unavailability (e.g., Maintenance, Holiday).

  • start_time (str) – Earliest possible start of day in HH:MM format.

  • end_time (str) – Latest possible end of day in HH:MM format.

  • break_start_minimum (str) – Earliest time after start of work when break can begin in HH:MM format.

  • break_end_maximum (str) – Latest time after start of work when break must end in HH:MM format.

  • break_duration (str) – Duration of the break in HH:MM format.

  • capacity_kg (int) – Weight capacity of the vehicle in kilograms.

  • capacity_pallets (int) – Pallet capacity of the vehicle.

  • max_trips (int) – Maximum number of trips the vehicle can perform in a day.

  • max_working_time (str) – Maximum working time allowed for the vehicle in HH:MM format.

  • max_overtime_time (str) – Maximum overtime allowed for the vehicle in HH:MM format.

  • start_time_flexibility (str) – Flexibility for the start time in HH:MM format.

  • depot_out_time (str) – Time taken to prepare the vehicle for departure from the depot in HH:MM format.

  • depot_in_time (str) – Time taken to prepare the vehicle for arrival at the depot in HH:MM format.

  • cost_per_km (float) – Cost per kilometer for operating the vehicle in cents.

  • cost_per_minute (float) – Cost per minute for operating the vehicle in cents.

  • cost_per_overtime_minute (float) – Cost per minute of overtime for operating the vehicle in cents.

  • tags (Set[str]) – Tag IDs associated with the vehicle.

  • width_m (float) – Width of the vehicle in meters.

  • length_m (float) – Length of the vehicle in meters.

  • height_m (float) – Height of the vehicle in meters.

Example

Create a vehicle instance:

>>> vehicle = Vehicle(
...     id="vehicle_1",
...     type="VAN",
...     start_depot_id="depot_1",
...     end_depot_id="depot_1",
...     is_available=True,
...     start_time="08:00",
...     end_time="18:00",
...     capacity_kg=1000,
...     capacity_pallets=10,
...     max_trips=5,
...     max_working_time="10:00",
...     cost_per_km=0.5,
...     cost_per_minute=0.2,
...     tags={"AIRPORT", "REFRIGERATED"},
...     width_m=2.0,
...     length_m=5.0,
...     height_m=2.5
... )

Personnel

class Personnel

Represents a person (driver or helper) available for assignments in the environment.

Variables:
  • id (str) – Unique identifier for the personnel.

  • type (Literal["DRIVER", "HELPER"]) – Type of personnel.

  • compatible_vehicle_types (Set[str]) – Vehicle types this person can operate (e.g., VAN, TRUCK).

  • tags (Set[str]) – Tag IDs for matching or filtering.

  • is_available (bool) – Whether the personnel is currently available for assignment.

  • start_time (str) – Start of availability in HH:MM format.

  • end_time (str) – End of availability in HH:MM format.

  • max_working_time (str) – Maximum working time available in HH:MM format.

  • name (str) – Display name of the personnel (e.g., full name).

  • phone (Optional[str]) – Phone number for the personnel.

  • notes (Optional[str]) – Notes about the personnel (e.g., preferences, restrictions).

Example

>>> personnel = Personnel(
...     id="driver_1",
...     type="DRIVER",
...     compatible_vehicle_types={"VAN", "TRUCK"},
...     tags={"CERTIFIED_DRIVER"},
...     is_available=True,
...     start_time="08:00",
...     end_time="18:00",
...     max_working_time="10:00",
...     name="John Doe",
...     phone="+1234567890",
...     notes="Prefers morning shifts"
... )

Orders

class Order

Represents a pickup or delivery task, including location, goods, time windows, and constraints.

Variables:
  • id (str) – Unique identifier for the order.

  • node_id (str) – Identifier of the graph node where the order is located.

  • latitude (float) – Latitude of the order location in decimal degrees.

  • longitude (float) – Longitude of the order location in decimal degrees.

  • input_weight (float) – Weight in kilograms to be picked up.

  • input_volume (float) – Volume in cubic meters to be picked up.

  • input_pallets (int) – Number of pallets to be picked up.

  • output_weight (float) – Weight in kilograms to be delivered.

  • output_volume (float) – Volume in cubic meters to be delivered.

  • output_pallets (int) – Number of pallets to be delivered.

  • time_windows (Set[str]) – Set of time windows for delivery in HH:MM-HH:MM format.

  • fixed_service_time (str) – Fixed service time required at the location in HH:MM format.

  • variable_service_time (str) – Additional variable service time in HH:MM format.

  • tags (Set[str]) – Tag IDs for indirect capabilities or constraints.

  • allowed_vehicle_types (Set[str]) – Vehicle types explicitly allowed to service this order.

  • helper_required (bool) – Whether a helper is required to service this order.

  • name (str) – Display name for the order (e.g., customer name or location name).

  • shipment_number (str) – Shipment number associated with the order.

  • customer_category (str) – Category of the customer (e.g., Premium, Standard).

  • sales_document_type (str) – Type of sales document (e.g., TypeA).

  • address_street (str) – Street address.

  • address_city (str) – City name.

  • address_postal_code (str) – Postal code.

  • address_country (str) – Country code (ISO 3166-1 alpha-2).

Example

>>> order = Order(
...     id="order_1",
...     node_id="node_123",
...     latitude=37.7749,
...     longitude=-122.4194,
...     input_weight=100.0,
...     output_weight=0.0,
...     time_windows={"09:00-11:00", "14:00-16:00"},
...     fixed_service_time="00:30",
...     tags={"FRAGILE"},
...     allowed_vehicle_types={"VAN"},
...     helper_required=False,
...     name="Customer A",
...     shipment_number="SHIP123",
...     customer_category="Premium",
...     sales_document_type="TypeA",
...     address_street="123 Main St",
...     address_city="San Francisco",
...     address_postal_code="94103",
...     address_country="US"
... )

Tags

class Tag

Represents a tag for adding constraints or capabilities to orders, vehicles, or personnel.

Variables:
  • id (str) – Unique identifier for the tag.

  • function (Literal["FIRST", "LAST", "NONE"]) – How this tag affects the route.

Example

>>> tag = Tag(
...     id="REFRIGERATED",
...     function="NONE"
... )

Solution

The Solution contains the computed routes with their hierarchy. Violations can appear at any level:

        flowchart TB
   Sol[Solution] -->|"routes: Dict"| R[Route]
   R -->|"trips: List"| Tr[Trip]
   Tr -->|"stops: List"| St[Stop]

   Sol -.->|"violations: Set"| Vio[Violation]
   R -.->|"violations: Set"| Vio
   Tr -.->|"violations: Set"| Vio
   St -.->|"violations: Set"| Vio

   style Sol fill:#D97B4A,color:#fff
   style R fill:#E8A87C
   style Tr fill:#F0C8A8
   style St fill:#F5DCC8
   style Vio fill:#D94A4A,color:#fff
    
class Solution

The solution to a routing problem including routes, KPIs, and violations.

Variables:
  • routes (Dict[str, Route]) – Dictionary of routes keyed by route id.

  • kpis (Dict[str, Union[int, float, bool]]) – KPI metrics for this solution.

  • violations (Dict[ViolationCode, SetDiffs[Violation]]) – Violations grouped by code.

Example

>>> solution = Solution(
...     routes={"vehicle_1": route1, "vehicle_2": route2},
...     kpis={"distance_m": 100000, "duration_min": 480},
...     violations={}
... )

Violations

Violations track constraint breaches at any level of the solution hierarchy.

class Violation

Represents a violation detected in the solution.

Variables:
  • id (str) – Unique identifier for the violation, auto-generated as a hash of the violation content.

  • placeholders (Dict[str, str]) – Dictionary of placeholder values for this violation.

  • severity (ViolationSeverity) – Severity level of the violation.

Example

>>> violation = Violation(
...     placeholders={"vehicle_id": "vehicle_1", "max_load": "1000kg"},
...     severity=ViolationSeverity.HIGH
... )
class ViolationCode

ViolationCode is an enumeration that represents various types of violation codes that can occur in the system. Each violation code is a string value that corresponds to a specific type of constraint or rule violation.

Variables:
  • TIME_WINDOW (str) – Represents a violation related to time window constraints.

  • CAPACITY (str) – Represents a violation related to capacity constraints.

  • SKILL (str) – Represents a violation related to skill requirements.

  • MISSING_HELPER (str) – Represents a violation where a required helper is missing.

  • ACCESSIBILITY (str) – Represents a violation related to accessibility constraints.

  • MAX_TIME (str) – Represents a violation where the maximum allowable time is exceeded.

class ViolationSeverity

ViolationSeverity is an enumeration that represents the severity levels of violations in the system. Each severity level is a string value that indicates the seriousness of the violation.

Variables:
  • WARNING (str) – Indicates a warning-level violation.

  • CRITICAL (str) – Indicates a critical-level violation.

Routes

A route represents the full assignment of a vehicle with driver and optional helper.

class Route

Represents a route assigned to a vehicle with associated trips and violations.

Variables:
  • vehicle_id (str) – Unique identifier for the vehicle assigned to the route.

  • driver_id (str) – Identifier for the driver assigned to the vehicle.

  • helper_id (Optional[str]) – Identifier for the helper assigned to the vehicle, if any.

  • trips (Dict[str, Trip]) – Dictionary of trips keyed by trip index.

  • kpis (Dict[str, Union[int, float, bool]]) – KPI metrics for this route.

  • violations (Dict[ViolationCode, Dict[str, Violation]]) – Violations grouped by code.

Example

>>> route = Route(
...     vehicle_id="vehicle_1",
...     driver_id="driver_1",
...     helper_id="helper_1",
...     trips={"0": trip1, "1": trip2},
...     kpis={"distance_m": 50000, "duration_min": 240},
...     violations={}
... )

Trips

A trip is a single round-trip from depot to depot within a route.

class Trip

Represents a trip (a sequence of stops) and its operational KPIs.

Variables:
  • vehicle_id (str) – Identifier of the vehicle assigned to the trip.

  • stops (Dict[str, Stop]) – Dictionary of Stop objects keyed by stop index.

  • kpis (Dict[str, Union[int, float, bool]]) – KPI metrics for this trip.

  • violations (Dict[ViolationCode, Dict[str, Violation]]) – Violations grouped by code.

Example

>>> trip = Trip(
...     vehicle_id="vehicle_1",
...     stops={"0": stop1, "1": stop2, "2": stop3},
...     kpis={"distance_m": 25000, "duration_min": 120},
...     violations={}
... )

Stops

A stop represents a single location visit within a trip.

class Stop

Representation of a route stop including timing, load, KPI metrics, violations and user metadata.

Variables:
  • type (StopType) – Type of stop.

  • node_id (str) – Identifier referencing the node for this stop.

  • location_id (str) – Identifier referencing the location for this stop.

  • shipment_number (int) – Shipment sequence or identifier number associated with the stop.

  • departure_time (str) – Departure time from the stop in HH:MM format.

  • arrival_time (str) – Arrival time at the stop in HH:MM format.

  • waiting_time (str) – Waiting time at the stop in HH:MM format.

  • load_after_servicing (str) – Load on board after servicing this stop.

  • break_taken (bool) – Whether a break was taken at this stop.

  • pinned (bool) – User flag indicating the stop is pinned/prioritized.

  • kpis (Dict[str, Union[int, float, bool]]) – KPI metrics for this stop.

  • violations (Dict[ViolationCode, Dict[str, Violation]]) – Violations grouped by code.

Example

>>> stop = Stop(
...     type=StopType.PICKUP,
...     node_id="node_123",
...     location_id="loc_456",
...     shipment_number=1,
...     departure_time="10:30",
...     arrival_time="10:00",
...     waiting_time="00:15",
...     load_after_servicing="500kg",
...     break_taken=False,
...     pinned=True,
...     kpis={"distance_m": 10000, "duration_min": 60},
...     violations={}
... )

Examples

Example 1: Creating a state with environment and solution

from pyutils.data_adapter.state.dora.base import State
from pyutils.data_adapter.state.dora.definitions import (
    Environment,
    Vehicle,
    Personnel,
    Order,
    Tag,
    Solution,
    Route,
    Trip,
    Stop,
    Violation,
)

# Create state and populate it from the state service
state = State(id="state_001", entity='SOLVER')
state.populate()

# Create environment entities
vehicleA = Vehicle(...)
vehicleB = Vehicle(...)
personnelA = Personnel(...)
personnelB = Personnel(...)
orderA = Order(...)
orderB = Order(...)
tagA = Tag(...)
tagB = Tag(...)

# Add the entities to the environment
state.environment.add_vehicle(vehicleA)
state.environment.fleet[vehicleB.id] = vehicleB  # Alternative way to add vehicle
state.environment.add_personnel(personnelA)
state.environment.personnel[personnelB.id] = personnelB  # Alternative way to add personnel
state.environment.add_order(orderA)
state.environment.orders[orderB.id] = orderB  # Alternative way to add order
state.environment.add_tag(tagA)
state.environment.tags[tagB.id] = tagB  # Alternative way to add tag

# Create solution entities
stopA = Stop(...)
stopB = Stop(...)
trip = Trip(..., stops=[stopA, stopB])
route = Route(id="vehicle_123", ..., trips=[trip])
violation = Violation(...)

# Create solution
state.solution.violations.add(violation)
state.solution.routes[route.id] = route

# Save the solution back to the state service
state.save()

This example will produce the following state:

State
├── Environment
│   ├── Fleet
│   │   ├── Vehicle A
│   │   └── Vehicle B
│   ├── Personnel
│   │   ├── Personnel A
│   │   └── Personnel B
│   ├── Orders
│   │   ├── Order A
│   │   └── Order B
│   └── Tags
│       ├── Tag A
│       └── Tag B
└── Solution
    ├── Violations
    │   └── Violation 1
    └── Routes
        └── Route for Vehicle 123
            └── Trips
                └── Trip 1
                    ├── Stop A
                    └── Stop B

Example 2: Modifying an existing state

# Assume state is already created and populated
state = State(id="state_001", entity='SOLVER')
state.populate()

# Modify an existing order
state.environment.orders["Order A"].latitude = 40.7128
state.environment.orders["Order A"].longitude = -74.0060
state.environment.orders["Order A"].tags.append("priority")
state.environment.orders["Order A"].tags.remove("fragile")

# Remove a vehicle from the fleet
state.environment.remove_vehicle("Vehicle A")
del state.environment.fleet["Vehicle A"] # Alternative way to remove vehicle

# Add a new route to the solution
new_stop = Stop(...)
new_trip = Trip(..., stops=[new_stop])
new_route = Route(id="vehicle_789", ..., trips=[new_trip])
state.solution.routes[new_route.id] = new_route

# Modify an existing trip
stopA = Stop(...)
stopB = Stop(...)
state.solution.routes["vehicle_123"].trips[0].stops = [stopA, stopB]

# Save the updated state back to the state service
state.save()

This example instead produces the following updated state:

State
├── Environment
│   ├── Fleet
│   │   └── Vehicle B
│   ├── Personnel
│   │   ├── Personnel A
│   │   └── Personnel B
│   ├── Orders
│   │   ├── Order A (modified)
│   │   └── Order B
│   └── Tags
│       ├── Tag A
│       └── Tag B
└── Solution
    ├── Violations
    │   └── Violation 1
    └── Routes
        ├── Route for Vehicle 123 (modified)
        │   └── Trips
        │       └── Trip 1 (modified)
        │           ├── Stop A
        │           └── Stop B
        └── Route for Vehicle 789 (new)
            └── Trips
                └── Trip 1
                    └── New Stop