Struct ProblemBuilder

Source
pub struct ProblemBuilder { /* private fields */ }
Expand description

Provides way to build a VRP definition.

Implementations§

Source§

impl ProblemBuilder

Source

pub fn add_job(self, job: Job) -> Self

Adds a job to the collection of the things to be done.

Source

pub fn add_jobs(self, jobs: impl Iterator<Item = Job>) -> Self

Adds multiple jobs to the collection of the things to be done.

Examples found in repository?
examples/custom_objective.rs (line 109)
84fn define_problem(goal: GoalContext, transport: Arc<dyn TransportCost>) -> GenericResult<Problem> {
85    // create 4 jobs where two are having top prio
86    let single_jobs = (1..=4)
87        .map(|idx| {
88            SingleBuilder::default()
89                .id(format!("job{idx}").as_str())
90                .demand(Demand::delivery(1))
91                .dimension(|dimens| {
92                    // mark two jobs as top priority (2 and 4 locations)
93                    dimens.set_job_priority(idx % 2 == 0);
94                })
95                .location(idx)?
96                .build_as_job()
97        })
98        .collect::<Result<Vec<_>, _>>()?;
99
100    // define a single vehicle with limited capacity which doesn't need to return back to the depot
101    let vehicle = VehicleBuilder::default()
102        .id("v1".to_string().as_str())
103        .add_detail(VehicleDetailBuilder::default().set_start_location(0).build()?)
104        // only two jobs can be served by the vehicle
105        .capacity(SingleDimLoad::new(2))
106        .build()?;
107
108    ProblemBuilder::default()
109        .add_jobs(single_jobs.into_iter())
110        .add_vehicles(once(vehicle))
111        .with_goal(goal)
112        .with_transport_cost(transport)
113        .build()
114}
More examples
Hide additional examples
examples/cvrp.rs (line 54)
20fn define_problem(goal: GoalContext, transport: Arc<dyn TransportCost>) -> GenericResult<Problem> {
21    // create 4 jobs with location indices from 1 to 4
22    let single_jobs = (1..=4)
23        .map(|idx| {
24            SingleBuilder::default()
25                .id(format!("job{idx}").as_str())
26                // each job is delivery job with demand=1
27                .demand(Demand::delivery(1))
28                // job has location, which is an index in routing matrix
29                .location(idx)?
30                .build_as_job()
31        })
32        .collect::<Result<Vec<_>, _>>()?;
33
34    // create 4 vehicles
35    let vehicles = (1..=4)
36        .map(|idx| {
37            VehicleBuilder::default()
38                .id(format!("v{idx}").as_str())
39                .add_detail(
40                    VehicleDetailBuilder::default()
41                        // vehicle starts at location with index 0 in routing matrix
42                        .set_start_location(0)
43                        // vehicle should return to location with index 0
44                        .set_end_location(0)
45                        .build()?,
46                )
47                // each vehicle has capacity=2, so it can serve at most 2 jobs
48                .capacity(SingleDimLoad::new(2))
49                .build()
50        })
51        .collect::<Result<Vec<_>, _>>()?;
52
53    ProblemBuilder::default()
54        .add_jobs(single_jobs.into_iter())
55        .add_vehicles(vehicles.into_iter())
56        .with_goal(goal)
57        .with_transport_cost(transport)
58        .build()
59}
examples/custom_constraint.rs (line 94)
52fn define_problem(goal: GoalContext, transport: Arc<dyn TransportCost>) -> GenericResult<Problem> {
53    // create 4 jobs when second and forth have fridge requirement
54    let single_jobs = (1..=4)
55        .map(|idx| {
56            SingleBuilder::default()
57                .id(format!("job{idx}").as_str())
58                .demand(Demand::delivery(1))
59                .dimension(|dimens| {
60                    // all jobs have fridge requirements, but only one vehicle will be allowed to serve them
61                    dimens.set_job_hardware("fridge".to_string());
62                })
63                .location(idx)?
64                .build_as_job()
65        })
66        .collect::<Result<Vec<_>, _>>()?;
67
68    // create 2 vehicles
69    let vehicles = (1..=2)
70        .map(|idx| {
71            VehicleBuilder::default()
72                .id(format!("v{idx}").as_str())
73                .add_detail(
74                    VehicleDetailBuilder::default()
75                        // vehicle starts at location with index 0 in routing matrix
76                        .set_start_location(0)
77                        // vehicle should return to location with index 0
78                        .set_end_location(0)
79                        .build()?,
80                )
81                .dimension(|dimens| {
82                    if idx % 2 == 0 {
83                        // only one vehicle has a hardware requirement set to 'fridge'
84                        dimens.set_vehicle_hardware(once("fridge".to_string()).collect());
85                    }
86                })
87                // each vehicle has capacity=2, so it can serve at most 2 jobs
88                .capacity(SingleDimLoad::new(2))
89                .build()
90        })
91        .collect::<Result<Vec<_>, _>>()?;
92
93    ProblemBuilder::default()
94        .add_jobs(single_jobs.into_iter())
95        .add_vehicles(vehicles.into_iter())
96        .with_goal(goal)
97        .with_transport_cost(transport)
98        .build()
99}
examples/pdptw.rs (line 67)
22fn define_problem(goal: GoalContext, transport: Arc<dyn TransportCost>) -> GenericResult<Problem> {
23    // build two PUDO (pick up/drop off) jobs with demand=1 and permissive time windows (just to show API usage)
24    let pudos = (1..=2)
25        .map(|idx| {
26            let location_idx = if idx == 1 { 1 } else { 3 };
27            MultiBuilder::default()
28                .id(format!("pudo{idx}").as_str())
29                .add_job(
30                    SingleBuilder::default()
31                        .demand(Demand::pudo_pickup(1))
32                        .times(vec![TimeWindow::new(0., 1000.)])?
33                        .duration(10.)?
34                        .location(location_idx)?
35                        .build()?,
36                )
37                .add_job(
38                    SingleBuilder::default()
39                        .demand(Demand::pudo_delivery(1))
40                        .times(vec![TimeWindow::new(0., 1000.)])?
41                        .duration(10.)?
42                        .location(location_idx + 1)?
43                        .build()?,
44                )
45                .build_as_job()
46        })
47        .collect::<Result<Vec<_>, _>>()?;
48
49    // define a single vehicle with limited capacity
50    let vehicle = VehicleBuilder::default()
51        .id("v1".to_string().as_str())
52        .add_detail(
53            VehicleDetailBuilder::default()
54                // vehicle starts at location with index 0 in routing matrix
55                .set_start_location(0)
56                .set_start_time(0.)
57                // vehicle should return to location with index 0
58                .set_end_location(0)
59                .set_end_time(10000.)
60                .build()?,
61        )
62        // the vehicle has capacity=1, so it is forced to do delivery after each pickup
63        .capacity(SingleDimLoad::new(1))
64        .build()?;
65
66    ProblemBuilder::default()
67        .add_jobs(pudos.into_iter())
68        .add_vehicles(once(vehicle))
69        .with_goal(goal)
70        .with_transport_cost(transport)
71        .build()
72}
Source

pub fn add_vehicle(self, vehicle: Vehicle) -> Self

Add a vehicle to the fleet. At least one has to be provided.

Source

pub fn add_vehicles(self, vehicles: impl Iterator<Item = Vehicle>) -> Self

Add multiple vehicles to the fleet. At least one has to be provided.

Examples found in repository?
examples/custom_objective.rs (line 110)
84fn define_problem(goal: GoalContext, transport: Arc<dyn TransportCost>) -> GenericResult<Problem> {
85    // create 4 jobs where two are having top prio
86    let single_jobs = (1..=4)
87        .map(|idx| {
88            SingleBuilder::default()
89                .id(format!("job{idx}").as_str())
90                .demand(Demand::delivery(1))
91                .dimension(|dimens| {
92                    // mark two jobs as top priority (2 and 4 locations)
93                    dimens.set_job_priority(idx % 2 == 0);
94                })
95                .location(idx)?
96                .build_as_job()
97        })
98        .collect::<Result<Vec<_>, _>>()?;
99
100    // define a single vehicle with limited capacity which doesn't need to return back to the depot
101    let vehicle = VehicleBuilder::default()
102        .id("v1".to_string().as_str())
103        .add_detail(VehicleDetailBuilder::default().set_start_location(0).build()?)
104        // only two jobs can be served by the vehicle
105        .capacity(SingleDimLoad::new(2))
106        .build()?;
107
108    ProblemBuilder::default()
109        .add_jobs(single_jobs.into_iter())
110        .add_vehicles(once(vehicle))
111        .with_goal(goal)
112        .with_transport_cost(transport)
113        .build()
114}
More examples
Hide additional examples
examples/cvrp.rs (line 55)
20fn define_problem(goal: GoalContext, transport: Arc<dyn TransportCost>) -> GenericResult<Problem> {
21    // create 4 jobs with location indices from 1 to 4
22    let single_jobs = (1..=4)
23        .map(|idx| {
24            SingleBuilder::default()
25                .id(format!("job{idx}").as_str())
26                // each job is delivery job with demand=1
27                .demand(Demand::delivery(1))
28                // job has location, which is an index in routing matrix
29                .location(idx)?
30                .build_as_job()
31        })
32        .collect::<Result<Vec<_>, _>>()?;
33
34    // create 4 vehicles
35    let vehicles = (1..=4)
36        .map(|idx| {
37            VehicleBuilder::default()
38                .id(format!("v{idx}").as_str())
39                .add_detail(
40                    VehicleDetailBuilder::default()
41                        // vehicle starts at location with index 0 in routing matrix
42                        .set_start_location(0)
43                        // vehicle should return to location with index 0
44                        .set_end_location(0)
45                        .build()?,
46                )
47                // each vehicle has capacity=2, so it can serve at most 2 jobs
48                .capacity(SingleDimLoad::new(2))
49                .build()
50        })
51        .collect::<Result<Vec<_>, _>>()?;
52
53    ProblemBuilder::default()
54        .add_jobs(single_jobs.into_iter())
55        .add_vehicles(vehicles.into_iter())
56        .with_goal(goal)
57        .with_transport_cost(transport)
58        .build()
59}
examples/custom_constraint.rs (line 95)
52fn define_problem(goal: GoalContext, transport: Arc<dyn TransportCost>) -> GenericResult<Problem> {
53    // create 4 jobs when second and forth have fridge requirement
54    let single_jobs = (1..=4)
55        .map(|idx| {
56            SingleBuilder::default()
57                .id(format!("job{idx}").as_str())
58                .demand(Demand::delivery(1))
59                .dimension(|dimens| {
60                    // all jobs have fridge requirements, but only one vehicle will be allowed to serve them
61                    dimens.set_job_hardware("fridge".to_string());
62                })
63                .location(idx)?
64                .build_as_job()
65        })
66        .collect::<Result<Vec<_>, _>>()?;
67
68    // create 2 vehicles
69    let vehicles = (1..=2)
70        .map(|idx| {
71            VehicleBuilder::default()
72                .id(format!("v{idx}").as_str())
73                .add_detail(
74                    VehicleDetailBuilder::default()
75                        // vehicle starts at location with index 0 in routing matrix
76                        .set_start_location(0)
77                        // vehicle should return to location with index 0
78                        .set_end_location(0)
79                        .build()?,
80                )
81                .dimension(|dimens| {
82                    if idx % 2 == 0 {
83                        // only one vehicle has a hardware requirement set to 'fridge'
84                        dimens.set_vehicle_hardware(once("fridge".to_string()).collect());
85                    }
86                })
87                // each vehicle has capacity=2, so it can serve at most 2 jobs
88                .capacity(SingleDimLoad::new(2))
89                .build()
90        })
91        .collect::<Result<Vec<_>, _>>()?;
92
93    ProblemBuilder::default()
94        .add_jobs(single_jobs.into_iter())
95        .add_vehicles(vehicles.into_iter())
96        .with_goal(goal)
97        .with_transport_cost(transport)
98        .build()
99}
examples/pdptw.rs (line 68)
22fn define_problem(goal: GoalContext, transport: Arc<dyn TransportCost>) -> GenericResult<Problem> {
23    // build two PUDO (pick up/drop off) jobs with demand=1 and permissive time windows (just to show API usage)
24    let pudos = (1..=2)
25        .map(|idx| {
26            let location_idx = if idx == 1 { 1 } else { 3 };
27            MultiBuilder::default()
28                .id(format!("pudo{idx}").as_str())
29                .add_job(
30                    SingleBuilder::default()
31                        .demand(Demand::pudo_pickup(1))
32                        .times(vec![TimeWindow::new(0., 1000.)])?
33                        .duration(10.)?
34                        .location(location_idx)?
35                        .build()?,
36                )
37                .add_job(
38                    SingleBuilder::default()
39                        .demand(Demand::pudo_delivery(1))
40                        .times(vec![TimeWindow::new(0., 1000.)])?
41                        .duration(10.)?
42                        .location(location_idx + 1)?
43                        .build()?,
44                )
45                .build_as_job()
46        })
47        .collect::<Result<Vec<_>, _>>()?;
48
49    // define a single vehicle with limited capacity
50    let vehicle = VehicleBuilder::default()
51        .id("v1".to_string().as_str())
52        .add_detail(
53            VehicleDetailBuilder::default()
54                // vehicle starts at location with index 0 in routing matrix
55                .set_start_location(0)
56                .set_start_time(0.)
57                // vehicle should return to location with index 0
58                .set_end_location(0)
59                .set_end_time(10000.)
60                .build()?,
61        )
62        // the vehicle has capacity=1, so it is forced to do delivery after each pickup
63        .capacity(SingleDimLoad::new(1))
64        .build()?;
65
66    ProblemBuilder::default()
67        .add_jobs(pudos.into_iter())
68        .add_vehicles(once(vehicle))
69        .with_goal(goal)
70        .with_transport_cost(transport)
71        .build()
72}
Source

pub fn with_vehicle_similarity( self, group_key_fn: impl Fn(&[Arc<Actor>]) -> Box<FleetGroupKeyFn> + 'static, ) -> Self

Sets a vehicle similarity function which allows grouping of similar vehicles together. That helps the solver to take more effective decisions job-vehicle assignment. Optional: when omitted, only vehicles with the same profile.index are grouped together.

Source

pub fn with_goal(self, goal: GoalContext) -> Self

Adds a goal of optimization. Use GoalContextBuilder to create the one. A required field.

Examples found in repository?
examples/custom_objective.rs (line 111)
84fn define_problem(goal: GoalContext, transport: Arc<dyn TransportCost>) -> GenericResult<Problem> {
85    // create 4 jobs where two are having top prio
86    let single_jobs = (1..=4)
87        .map(|idx| {
88            SingleBuilder::default()
89                .id(format!("job{idx}").as_str())
90                .demand(Demand::delivery(1))
91                .dimension(|dimens| {
92                    // mark two jobs as top priority (2 and 4 locations)
93                    dimens.set_job_priority(idx % 2 == 0);
94                })
95                .location(idx)?
96                .build_as_job()
97        })
98        .collect::<Result<Vec<_>, _>>()?;
99
100    // define a single vehicle with limited capacity which doesn't need to return back to the depot
101    let vehicle = VehicleBuilder::default()
102        .id("v1".to_string().as_str())
103        .add_detail(VehicleDetailBuilder::default().set_start_location(0).build()?)
104        // only two jobs can be served by the vehicle
105        .capacity(SingleDimLoad::new(2))
106        .build()?;
107
108    ProblemBuilder::default()
109        .add_jobs(single_jobs.into_iter())
110        .add_vehicles(once(vehicle))
111        .with_goal(goal)
112        .with_transport_cost(transport)
113        .build()
114}
More examples
Hide additional examples
examples/cvrp.rs (line 56)
20fn define_problem(goal: GoalContext, transport: Arc<dyn TransportCost>) -> GenericResult<Problem> {
21    // create 4 jobs with location indices from 1 to 4
22    let single_jobs = (1..=4)
23        .map(|idx| {
24            SingleBuilder::default()
25                .id(format!("job{idx}").as_str())
26                // each job is delivery job with demand=1
27                .demand(Demand::delivery(1))
28                // job has location, which is an index in routing matrix
29                .location(idx)?
30                .build_as_job()
31        })
32        .collect::<Result<Vec<_>, _>>()?;
33
34    // create 4 vehicles
35    let vehicles = (1..=4)
36        .map(|idx| {
37            VehicleBuilder::default()
38                .id(format!("v{idx}").as_str())
39                .add_detail(
40                    VehicleDetailBuilder::default()
41                        // vehicle starts at location with index 0 in routing matrix
42                        .set_start_location(0)
43                        // vehicle should return to location with index 0
44                        .set_end_location(0)
45                        .build()?,
46                )
47                // each vehicle has capacity=2, so it can serve at most 2 jobs
48                .capacity(SingleDimLoad::new(2))
49                .build()
50        })
51        .collect::<Result<Vec<_>, _>>()?;
52
53    ProblemBuilder::default()
54        .add_jobs(single_jobs.into_iter())
55        .add_vehicles(vehicles.into_iter())
56        .with_goal(goal)
57        .with_transport_cost(transport)
58        .build()
59}
examples/custom_constraint.rs (line 96)
52fn define_problem(goal: GoalContext, transport: Arc<dyn TransportCost>) -> GenericResult<Problem> {
53    // create 4 jobs when second and forth have fridge requirement
54    let single_jobs = (1..=4)
55        .map(|idx| {
56            SingleBuilder::default()
57                .id(format!("job{idx}").as_str())
58                .demand(Demand::delivery(1))
59                .dimension(|dimens| {
60                    // all jobs have fridge requirements, but only one vehicle will be allowed to serve them
61                    dimens.set_job_hardware("fridge".to_string());
62                })
63                .location(idx)?
64                .build_as_job()
65        })
66        .collect::<Result<Vec<_>, _>>()?;
67
68    // create 2 vehicles
69    let vehicles = (1..=2)
70        .map(|idx| {
71            VehicleBuilder::default()
72                .id(format!("v{idx}").as_str())
73                .add_detail(
74                    VehicleDetailBuilder::default()
75                        // vehicle starts at location with index 0 in routing matrix
76                        .set_start_location(0)
77                        // vehicle should return to location with index 0
78                        .set_end_location(0)
79                        .build()?,
80                )
81                .dimension(|dimens| {
82                    if idx % 2 == 0 {
83                        // only one vehicle has a hardware requirement set to 'fridge'
84                        dimens.set_vehicle_hardware(once("fridge".to_string()).collect());
85                    }
86                })
87                // each vehicle has capacity=2, so it can serve at most 2 jobs
88                .capacity(SingleDimLoad::new(2))
89                .build()
90        })
91        .collect::<Result<Vec<_>, _>>()?;
92
93    ProblemBuilder::default()
94        .add_jobs(single_jobs.into_iter())
95        .add_vehicles(vehicles.into_iter())
96        .with_goal(goal)
97        .with_transport_cost(transport)
98        .build()
99}
examples/pdptw.rs (line 69)
22fn define_problem(goal: GoalContext, transport: Arc<dyn TransportCost>) -> GenericResult<Problem> {
23    // build two PUDO (pick up/drop off) jobs with demand=1 and permissive time windows (just to show API usage)
24    let pudos = (1..=2)
25        .map(|idx| {
26            let location_idx = if idx == 1 { 1 } else { 3 };
27            MultiBuilder::default()
28                .id(format!("pudo{idx}").as_str())
29                .add_job(
30                    SingleBuilder::default()
31                        .demand(Demand::pudo_pickup(1))
32                        .times(vec![TimeWindow::new(0., 1000.)])?
33                        .duration(10.)?
34                        .location(location_idx)?
35                        .build()?,
36                )
37                .add_job(
38                    SingleBuilder::default()
39                        .demand(Demand::pudo_delivery(1))
40                        .times(vec![TimeWindow::new(0., 1000.)])?
41                        .duration(10.)?
42                        .location(location_idx + 1)?
43                        .build()?,
44                )
45                .build_as_job()
46        })
47        .collect::<Result<Vec<_>, _>>()?;
48
49    // define a single vehicle with limited capacity
50    let vehicle = VehicleBuilder::default()
51        .id("v1".to_string().as_str())
52        .add_detail(
53            VehicleDetailBuilder::default()
54                // vehicle starts at location with index 0 in routing matrix
55                .set_start_location(0)
56                .set_start_time(0.)
57                // vehicle should return to location with index 0
58                .set_end_location(0)
59                .set_end_time(10000.)
60                .build()?,
61        )
62        // the vehicle has capacity=1, so it is forced to do delivery after each pickup
63        .capacity(SingleDimLoad::new(1))
64        .build()?;
65
66    ProblemBuilder::default()
67        .add_jobs(pudos.into_iter())
68        .add_vehicles(once(vehicle))
69        .with_goal(goal)
70        .with_transport_cost(transport)
71        .build()
72}
Source

pub fn with_transport_cost(self, transport: Arc<dyn TransportCost>) -> Self

Adds a transport distance/duration estimation logic. A typical implementation will normally wrap routing distance/duration matrices. A required field.

Examples found in repository?
examples/custom_objective.rs (line 112)
84fn define_problem(goal: GoalContext, transport: Arc<dyn TransportCost>) -> GenericResult<Problem> {
85    // create 4 jobs where two are having top prio
86    let single_jobs = (1..=4)
87        .map(|idx| {
88            SingleBuilder::default()
89                .id(format!("job{idx}").as_str())
90                .demand(Demand::delivery(1))
91                .dimension(|dimens| {
92                    // mark two jobs as top priority (2 and 4 locations)
93                    dimens.set_job_priority(idx % 2 == 0);
94                })
95                .location(idx)?
96                .build_as_job()
97        })
98        .collect::<Result<Vec<_>, _>>()?;
99
100    // define a single vehicle with limited capacity which doesn't need to return back to the depot
101    let vehicle = VehicleBuilder::default()
102        .id("v1".to_string().as_str())
103        .add_detail(VehicleDetailBuilder::default().set_start_location(0).build()?)
104        // only two jobs can be served by the vehicle
105        .capacity(SingleDimLoad::new(2))
106        .build()?;
107
108    ProblemBuilder::default()
109        .add_jobs(single_jobs.into_iter())
110        .add_vehicles(once(vehicle))
111        .with_goal(goal)
112        .with_transport_cost(transport)
113        .build()
114}
More examples
Hide additional examples
examples/cvrp.rs (line 57)
20fn define_problem(goal: GoalContext, transport: Arc<dyn TransportCost>) -> GenericResult<Problem> {
21    // create 4 jobs with location indices from 1 to 4
22    let single_jobs = (1..=4)
23        .map(|idx| {
24            SingleBuilder::default()
25                .id(format!("job{idx}").as_str())
26                // each job is delivery job with demand=1
27                .demand(Demand::delivery(1))
28                // job has location, which is an index in routing matrix
29                .location(idx)?
30                .build_as_job()
31        })
32        .collect::<Result<Vec<_>, _>>()?;
33
34    // create 4 vehicles
35    let vehicles = (1..=4)
36        .map(|idx| {
37            VehicleBuilder::default()
38                .id(format!("v{idx}").as_str())
39                .add_detail(
40                    VehicleDetailBuilder::default()
41                        // vehicle starts at location with index 0 in routing matrix
42                        .set_start_location(0)
43                        // vehicle should return to location with index 0
44                        .set_end_location(0)
45                        .build()?,
46                )
47                // each vehicle has capacity=2, so it can serve at most 2 jobs
48                .capacity(SingleDimLoad::new(2))
49                .build()
50        })
51        .collect::<Result<Vec<_>, _>>()?;
52
53    ProblemBuilder::default()
54        .add_jobs(single_jobs.into_iter())
55        .add_vehicles(vehicles.into_iter())
56        .with_goal(goal)
57        .with_transport_cost(transport)
58        .build()
59}
examples/custom_constraint.rs (line 97)
52fn define_problem(goal: GoalContext, transport: Arc<dyn TransportCost>) -> GenericResult<Problem> {
53    // create 4 jobs when second and forth have fridge requirement
54    let single_jobs = (1..=4)
55        .map(|idx| {
56            SingleBuilder::default()
57                .id(format!("job{idx}").as_str())
58                .demand(Demand::delivery(1))
59                .dimension(|dimens| {
60                    // all jobs have fridge requirements, but only one vehicle will be allowed to serve them
61                    dimens.set_job_hardware("fridge".to_string());
62                })
63                .location(idx)?
64                .build_as_job()
65        })
66        .collect::<Result<Vec<_>, _>>()?;
67
68    // create 2 vehicles
69    let vehicles = (1..=2)
70        .map(|idx| {
71            VehicleBuilder::default()
72                .id(format!("v{idx}").as_str())
73                .add_detail(
74                    VehicleDetailBuilder::default()
75                        // vehicle starts at location with index 0 in routing matrix
76                        .set_start_location(0)
77                        // vehicle should return to location with index 0
78                        .set_end_location(0)
79                        .build()?,
80                )
81                .dimension(|dimens| {
82                    if idx % 2 == 0 {
83                        // only one vehicle has a hardware requirement set to 'fridge'
84                        dimens.set_vehicle_hardware(once("fridge".to_string()).collect());
85                    }
86                })
87                // each vehicle has capacity=2, so it can serve at most 2 jobs
88                .capacity(SingleDimLoad::new(2))
89                .build()
90        })
91        .collect::<Result<Vec<_>, _>>()?;
92
93    ProblemBuilder::default()
94        .add_jobs(single_jobs.into_iter())
95        .add_vehicles(vehicles.into_iter())
96        .with_goal(goal)
97        .with_transport_cost(transport)
98        .build()
99}
examples/pdptw.rs (line 70)
22fn define_problem(goal: GoalContext, transport: Arc<dyn TransportCost>) -> GenericResult<Problem> {
23    // build two PUDO (pick up/drop off) jobs with demand=1 and permissive time windows (just to show API usage)
24    let pudos = (1..=2)
25        .map(|idx| {
26            let location_idx = if idx == 1 { 1 } else { 3 };
27            MultiBuilder::default()
28                .id(format!("pudo{idx}").as_str())
29                .add_job(
30                    SingleBuilder::default()
31                        .demand(Demand::pudo_pickup(1))
32                        .times(vec![TimeWindow::new(0., 1000.)])?
33                        .duration(10.)?
34                        .location(location_idx)?
35                        .build()?,
36                )
37                .add_job(
38                    SingleBuilder::default()
39                        .demand(Demand::pudo_delivery(1))
40                        .times(vec![TimeWindow::new(0., 1000.)])?
41                        .duration(10.)?
42                        .location(location_idx + 1)?
43                        .build()?,
44                )
45                .build_as_job()
46        })
47        .collect::<Result<Vec<_>, _>>()?;
48
49    // define a single vehicle with limited capacity
50    let vehicle = VehicleBuilder::default()
51        .id("v1".to_string().as_str())
52        .add_detail(
53            VehicleDetailBuilder::default()
54                // vehicle starts at location with index 0 in routing matrix
55                .set_start_location(0)
56                .set_start_time(0.)
57                // vehicle should return to location with index 0
58                .set_end_location(0)
59                .set_end_time(10000.)
60                .build()?,
61        )
62        // the vehicle has capacity=1, so it is forced to do delivery after each pickup
63        .capacity(SingleDimLoad::new(1))
64        .build()?;
65
66    ProblemBuilder::default()
67        .add_jobs(pudos.into_iter())
68        .add_vehicles(once(vehicle))
69        .with_goal(goal)
70        .with_transport_cost(transport)
71        .build()
72}
Source

pub fn with_activity_cost(self, activity: Arc<dyn ActivityCost>) -> Self

Adds an activity service time estimation logic. An optional field: SimpleActivityCost will be used by default.

Source

pub fn with_extras(self, extras: Extras) -> Self

Adds an extras: an extension mechanism to pass arbitrary properties associated within the problem definition. An optional field.

Source

pub fn with_logger(self, logger: InfoLogger) -> Self

Adds a logger to the problem definition.

Source

pub fn build(self) -> GenericResult<Problem>

Builds a problem definition. Returns Err in case of an invalid configuration.

Examples found in repository?
examples/custom_objective.rs (line 113)
84fn define_problem(goal: GoalContext, transport: Arc<dyn TransportCost>) -> GenericResult<Problem> {
85    // create 4 jobs where two are having top prio
86    let single_jobs = (1..=4)
87        .map(|idx| {
88            SingleBuilder::default()
89                .id(format!("job{idx}").as_str())
90                .demand(Demand::delivery(1))
91                .dimension(|dimens| {
92                    // mark two jobs as top priority (2 and 4 locations)
93                    dimens.set_job_priority(idx % 2 == 0);
94                })
95                .location(idx)?
96                .build_as_job()
97        })
98        .collect::<Result<Vec<_>, _>>()?;
99
100    // define a single vehicle with limited capacity which doesn't need to return back to the depot
101    let vehicle = VehicleBuilder::default()
102        .id("v1".to_string().as_str())
103        .add_detail(VehicleDetailBuilder::default().set_start_location(0).build()?)
104        // only two jobs can be served by the vehicle
105        .capacity(SingleDimLoad::new(2))
106        .build()?;
107
108    ProblemBuilder::default()
109        .add_jobs(single_jobs.into_iter())
110        .add_vehicles(once(vehicle))
111        .with_goal(goal)
112        .with_transport_cost(transport)
113        .build()
114}
More examples
Hide additional examples
examples/cvrp.rs (line 58)
20fn define_problem(goal: GoalContext, transport: Arc<dyn TransportCost>) -> GenericResult<Problem> {
21    // create 4 jobs with location indices from 1 to 4
22    let single_jobs = (1..=4)
23        .map(|idx| {
24            SingleBuilder::default()
25                .id(format!("job{idx}").as_str())
26                // each job is delivery job with demand=1
27                .demand(Demand::delivery(1))
28                // job has location, which is an index in routing matrix
29                .location(idx)?
30                .build_as_job()
31        })
32        .collect::<Result<Vec<_>, _>>()?;
33
34    // create 4 vehicles
35    let vehicles = (1..=4)
36        .map(|idx| {
37            VehicleBuilder::default()
38                .id(format!("v{idx}").as_str())
39                .add_detail(
40                    VehicleDetailBuilder::default()
41                        // vehicle starts at location with index 0 in routing matrix
42                        .set_start_location(0)
43                        // vehicle should return to location with index 0
44                        .set_end_location(0)
45                        .build()?,
46                )
47                // each vehicle has capacity=2, so it can serve at most 2 jobs
48                .capacity(SingleDimLoad::new(2))
49                .build()
50        })
51        .collect::<Result<Vec<_>, _>>()?;
52
53    ProblemBuilder::default()
54        .add_jobs(single_jobs.into_iter())
55        .add_vehicles(vehicles.into_iter())
56        .with_goal(goal)
57        .with_transport_cost(transport)
58        .build()
59}
examples/custom_constraint.rs (line 98)
52fn define_problem(goal: GoalContext, transport: Arc<dyn TransportCost>) -> GenericResult<Problem> {
53    // create 4 jobs when second and forth have fridge requirement
54    let single_jobs = (1..=4)
55        .map(|idx| {
56            SingleBuilder::default()
57                .id(format!("job{idx}").as_str())
58                .demand(Demand::delivery(1))
59                .dimension(|dimens| {
60                    // all jobs have fridge requirements, but only one vehicle will be allowed to serve them
61                    dimens.set_job_hardware("fridge".to_string());
62                })
63                .location(idx)?
64                .build_as_job()
65        })
66        .collect::<Result<Vec<_>, _>>()?;
67
68    // create 2 vehicles
69    let vehicles = (1..=2)
70        .map(|idx| {
71            VehicleBuilder::default()
72                .id(format!("v{idx}").as_str())
73                .add_detail(
74                    VehicleDetailBuilder::default()
75                        // vehicle starts at location with index 0 in routing matrix
76                        .set_start_location(0)
77                        // vehicle should return to location with index 0
78                        .set_end_location(0)
79                        .build()?,
80                )
81                .dimension(|dimens| {
82                    if idx % 2 == 0 {
83                        // only one vehicle has a hardware requirement set to 'fridge'
84                        dimens.set_vehicle_hardware(once("fridge".to_string()).collect());
85                    }
86                })
87                // each vehicle has capacity=2, so it can serve at most 2 jobs
88                .capacity(SingleDimLoad::new(2))
89                .build()
90        })
91        .collect::<Result<Vec<_>, _>>()?;
92
93    ProblemBuilder::default()
94        .add_jobs(single_jobs.into_iter())
95        .add_vehicles(vehicles.into_iter())
96        .with_goal(goal)
97        .with_transport_cost(transport)
98        .build()
99}
examples/pdptw.rs (line 71)
22fn define_problem(goal: GoalContext, transport: Arc<dyn TransportCost>) -> GenericResult<Problem> {
23    // build two PUDO (pick up/drop off) jobs with demand=1 and permissive time windows (just to show API usage)
24    let pudos = (1..=2)
25        .map(|idx| {
26            let location_idx = if idx == 1 { 1 } else { 3 };
27            MultiBuilder::default()
28                .id(format!("pudo{idx}").as_str())
29                .add_job(
30                    SingleBuilder::default()
31                        .demand(Demand::pudo_pickup(1))
32                        .times(vec![TimeWindow::new(0., 1000.)])?
33                        .duration(10.)?
34                        .location(location_idx)?
35                        .build()?,
36                )
37                .add_job(
38                    SingleBuilder::default()
39                        .demand(Demand::pudo_delivery(1))
40                        .times(vec![TimeWindow::new(0., 1000.)])?
41                        .duration(10.)?
42                        .location(location_idx + 1)?
43                        .build()?,
44                )
45                .build_as_job()
46        })
47        .collect::<Result<Vec<_>, _>>()?;
48
49    // define a single vehicle with limited capacity
50    let vehicle = VehicleBuilder::default()
51        .id("v1".to_string().as_str())
52        .add_detail(
53            VehicleDetailBuilder::default()
54                // vehicle starts at location with index 0 in routing matrix
55                .set_start_location(0)
56                .set_start_time(0.)
57                // vehicle should return to location with index 0
58                .set_end_location(0)
59                .set_end_time(10000.)
60                .build()?,
61        )
62        // the vehicle has capacity=1, so it is forced to do delivery after each pickup
63        .capacity(SingleDimLoad::new(1))
64        .build()?;
65
66    ProblemBuilder::default()
67        .add_jobs(pudos.into_iter())
68        .add_vehicles(once(vehicle))
69        .with_goal(goal)
70        .with_transport_cost(transport)
71        .build()
72}

Trait Implementations§

Source§

impl Default for ProblemBuilder

Source§

fn default() -> ProblemBuilder

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V