Attributes#
Attributes define problem features and automatically enable matching constraint generators and evaluators.
Available Attributes#
Attribute |
Entity |
Description |
|---|---|---|
GeoNode |
Node |
x, y coordinates for distance calculation |
Consumer |
Client |
Demand at a client |
Stock |
Vehicle |
Vehicle capacity |
Rendezvous |
Node |
Time window bounds (earliest, latest) |
ServiceQuery |
Client |
Service time at a node |
Profiter |
Client |
Profit value for orienteering problems (TOP) |
Pickup |
Client |
Pickup demand for pickup & delivery |
Delivery |
Client |
Delivery demand for pickup & delivery |
Synced |
Client |
Temporal synchronization constraints |
SoftTimeWindows |
Client |
Penalty-based soft time windows |
Problem Variants by Attributes#
Problem |
Required Attributes |
|---|---|
TSP |
|
VRP |
|
CVRP |
|
VRPTW |
|
CVRPTW |
|
TOP |
|
PDVRP |
|
VRPTWTD |
All above + |
Usage#
Python - Low-Level API#
Python uses helper functions to set attributes on entities:
import routing
routing.init()
# Create problem
problem = routing.Problem()
# Add depot and set its attributes
depot = problem.add_depot(0)
routing.set_depot_location(depot, 0.0, 0.0) # GeoNode
routing.set_depot_time_window(depot, 0.0, 1000.0) # Rendezvous
# Add client and set its attributes
client = problem.add_client(1)
routing.set_client_location(client, 10.0, 20.0) # GeoNode
routing.set_client_demand(client, 5) # Consumer
routing.set_client_time_window(client, 0.0, 200.0) # Rendezvous
routing.set_client_service_time(client, 10.0) # ServiceQuery
# Add vehicle and set its attributes
vehicle = problem.add_vehicle(0)
routing.set_vehicle_capacity(vehicle, 100) # Stock
# Enable the attributes used
problem.enable_attributes(["GeoNode", "Consumer", "Stock", "Rendezvous", "ServiceQuery"])
# Solve
solver = routing.create_solver("ga", problem)
solver.solve(30.0)
Python helper functions → Attributes:
Helper Function |
Attribute Set |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Python - ProblemBuilder (High-Level)#
The ProblemBuilder wraps the low-level API for convenience:
from routing.problem import ProblemBuilder
problem = (ProblemBuilder()
.with_depot(0, 0, tw_open=0, tw_close=1000)
.add_client(1, x=10, y=20, demand=5, tw_open=0, tw_close=200, service_time=10)
.add_vehicles(count=2, capacity=20)
.build()) # Automatically calls enable_attributes()
C++#
In C++, you use template methods to add attributes:
// 1. Enable the attributes you need
problem.enableAttributes<GeoNode, Consumer, Stock, Rendezvous, ServiceQuery>();
// 2. Add depot with attributes
auto* depot = problem.addDepot(0);
depot->addAttribute<GeoNode>(0.0, 0.0); // Coordinates
depot->addAttribute<Rendezvous>(0.0, 1000.0); // Operating hours
// 3. Add client with attributes
auto* client = problem.addClient(1);
client->addAttribute<GeoNode>(10.0, 20.0); // Coordinates
client->addAttribute<Consumer>(5); // Demand
client->addAttribute<Rendezvous>(0.0, 200.0); // Time window
client->addAttribute<ServiceQuery>(10.0); // Service time
// 4. Add vehicle with attributes
auto* vehicle = problem.addVehicle(0);
vehicle->addAttribute<Stock>(20); // Capacity
How Attributes Work#
When you add an attribute to an entity, the system automatically:
Registers the attribute with the problem
Enables constraint generators that depend on that attribute
Enables evaluators for solution quality assessment
Attribute Added → Constraint Generator Activated → Constraints in Model
↓
GeoNode → RoutingGenerator → Distance objective
Consumer → CapacityGenerator → Load ≤ Capacity
Stock → CapacityGenerator → Vehicle capacity limit
Rendezvous → TimeWindowGenerator → Arrival ∈ [open, close]
ServiceQuery → TimeWindowGenerator → Service time in scheduling
Custom Attributes#
You can define custom attributes using the CRTP pattern:
struct MyAttribute : public Attribute<MyAttribute> {
static constexpr const char* name() { return "MyAttribute"; }
double value;
explicit MyAttribute(double v) : value(v) {}
};
See Composable System for more details on extending the attribute system.