pub struct ProblemBuilder { /* private fields */ }
Expand description
Provides way to build a VRP definition.
Implementations§
Source§impl ProblemBuilder
impl ProblemBuilder
Sourcepub fn add_jobs(self, jobs: impl Iterator<Item = Job>) -> Self
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?
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
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}
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}
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}
Sourcepub fn add_vehicle(self, vehicle: Vehicle) -> Self
pub fn add_vehicle(self, vehicle: Vehicle) -> Self
Add a vehicle to the fleet. At least one has to be provided.
Sourcepub fn add_vehicles(self, vehicles: impl Iterator<Item = Vehicle>) -> Self
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?
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
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}
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}
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}
Sourcepub fn with_vehicle_similarity(
self,
group_key_fn: impl Fn(&[Arc<Actor>]) -> Box<FleetGroupKeyFn> + 'static,
) -> Self
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.
Sourcepub fn with_goal(self, goal: GoalContext) -> Self
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?
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
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}
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}
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}
Sourcepub fn with_transport_cost(self, transport: Arc<dyn TransportCost>) -> Self
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?
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
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}
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}
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}
Sourcepub fn with_activity_cost(self, activity: Arc<dyn ActivityCost>) -> Self
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.
Sourcepub fn with_extras(self, extras: Extras) -> Self
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.
Sourcepub fn with_logger(self, logger: InfoLogger) -> Self
pub fn with_logger(self, logger: InfoLogger) -> Self
Adds a logger to the problem definition.
Sourcepub fn build(self) -> GenericResult<Problem>
pub fn build(self) -> GenericResult<Problem>
Builds a problem definition. Returns Err in case of an invalid configuration.
Examples found in repository?
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
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}
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}
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
impl Default for ProblemBuilder
Source§fn default() -> ProblemBuilder
fn default() -> ProblemBuilder
Auto Trait Implementations§
impl Freeze for ProblemBuilder
impl !RefUnwindSafe for ProblemBuilder
impl !Send for ProblemBuilder
impl !Sync for ProblemBuilder
impl Unpin for ProblemBuilder
impl !UnwindSafe for ProblemBuilder
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
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