1use scirs2_core::ndarray::{Array1, Array2};
6use scirs2_core::random::prelude::*;
7use scirs2_core::random::prelude::*;
8
9use super::types::{
10 BinaryVehicleRoutingProblem, Customer, DistributionCenter, Supplier, SupplyChainNetwork,
11 SupplyChainOptimizer, TSPOptimizer, TimeWindow, VehicleRoutingOptimizer, Warehouse,
12};
13
14pub trait OptimizationProblem {
16 type Solution;
17 fn evaluate(&self, solution: &Self::Solution) -> f64;
19}
20pub fn create_benchmark_problems() -> Vec<BinaryVehicleRoutingProblem> {
22 let mut problems = Vec::new();
23 let small_distances = Array2::from_shape_vec(
24 (4, 4),
25 vec![
26 0.0, 10.0, 15.0, 20.0, 10.0, 0.0, 25.0, 30.0, 15.0, 25.0, 0.0, 35.0, 20.0, 30.0, 35.0,
27 0.0,
28 ],
29 )
30 .expect("Small benchmark distance matrix has valid shape");
31 let small_demands = Array1::from_vec(vec![0.0, 10.0, 15.0, 20.0]);
32 let small_optimizer =
33 VehicleRoutingOptimizer::new(small_distances.clone(), 50.0, small_demands.clone(), 2)
34 .expect("Small benchmark VRP has valid configuration");
35 problems.push(BinaryVehicleRoutingProblem::new(small_optimizer));
36 let medium_distances = Array2::from_shape_vec(
37 (6, 6),
38 vec![
39 0.0, 10.0, 15.0, 20.0, 25.0, 30.0, 10.0, 0.0, 25.0, 30.0, 35.0, 40.0, 15.0, 25.0, 0.0,
40 35.0, 40.0, 45.0, 20.0, 30.0, 35.0, 0.0, 45.0, 50.0, 25.0, 35.0, 40.0, 45.0, 0.0, 55.0,
41 30.0, 40.0, 45.0, 50.0, 55.0, 0.0,
42 ],
43 )
44 .expect("Medium benchmark distance matrix has valid shape");
45 let medium_demands = Array1::from_vec(vec![0.0, 12.0, 18.0, 22.0, 16.0, 14.0]);
46 let medium_optimizer = VehicleRoutingOptimizer::new(medium_distances, 60.0, medium_demands, 3)
47 .expect("Medium benchmark VRP has valid configuration");
48 problems.push(BinaryVehicleRoutingProblem::new(medium_optimizer));
49 let cvrptw_optimizer = VehicleRoutingOptimizer::new(small_distances, 40.0, small_demands, 2)
50 .expect("CVRPTW benchmark VRP has valid configuration")
51 .with_time_windows(vec![
52 TimeWindow {
53 start: 0.0,
54 end: 100.0,
55 service_time: 5.0,
56 },
57 TimeWindow {
58 start: 10.0,
59 end: 50.0,
60 service_time: 10.0,
61 },
62 TimeWindow {
63 start: 20.0,
64 end: 60.0,
65 service_time: 8.0,
66 },
67 TimeWindow {
68 start: 30.0,
69 end: 80.0,
70 service_time: 12.0,
71 },
72 ]);
73 problems.push(BinaryVehicleRoutingProblem::new(cvrptw_optimizer));
74 problems
75}
76#[cfg(test)]
77mod tests {
78 use super::*;
79 #[test]
80 fn test_vrp_optimizer() {
81 let distances = Array2::from_shape_vec(
82 (4, 4),
83 vec![
84 0.0, 10.0, 15.0, 20.0, 10.0, 0.0, 25.0, 30.0, 15.0, 25.0, 0.0, 35.0, 20.0, 30.0,
85 35.0, 0.0,
86 ],
87 )
88 .expect("Test distance matrix has valid shape");
89 let demands = Array1::from_vec(vec![0.0, 10.0, 15.0, 20.0]);
90 let optimizer = VehicleRoutingOptimizer::new(distances, 50.0, demands, 2)
91 .expect("Test VRP optimizer should be created with valid inputs");
92 let (_qubo, var_map) = optimizer
93 .build_qubo()
94 .expect("VRP QUBO should build successfully");
95 assert!(!var_map.is_empty());
96 }
97 #[test]
98 fn test_tsp_optimizer() {
99 let distances = Array2::from_shape_vec(
100 (4, 4),
101 vec![
102 0.0, 10.0, 15.0, 20.0, 10.0, 0.0, 25.0, 30.0, 15.0, 25.0, 0.0, 35.0, 20.0, 30.0,
103 35.0, 0.0,
104 ],
105 )
106 .expect("Test distance matrix has valid shape");
107 let optimizer =
108 TSPOptimizer::new(distances).expect("TSP optimizer should be created with valid input");
109 let (_qubo, var_map) = optimizer
110 .build_qubo()
111 .expect("TSP QUBO should build successfully");
112 assert_eq!(var_map.len(), 16);
113 }
114 #[test]
115 fn test_supply_chain() {
116 let network = SupplyChainNetwork {
117 suppliers: vec![Supplier {
118 id: 0,
119 capacity: 100.0,
120 cost_per_unit: 10.0,
121 lead_time: 2,
122 reliability: 0.95,
123 }],
124 warehouses: vec![Warehouse {
125 id: 0,
126 capacity: 200.0,
127 holding_cost: 1.0,
128 fixed_cost: 1000.0,
129 location: (0.0, 0.0),
130 }],
131 distribution_centers: vec![DistributionCenter {
132 id: 0,
133 capacity: 150.0,
134 processing_cost: 2.0,
135 location: (10.0, 10.0),
136 }],
137 customers: vec![Customer {
138 id: 0,
139 demand: Array1::from_vec(vec![20.0, 25.0, 30.0]),
140 priority: 1.0,
141 location: (20.0, 20.0),
142 }],
143 links: vec![],
144 };
145 let optimizer = SupplyChainOptimizer::new(network, 3);
146 let (_qubo, var_map) = optimizer
147 .build_qubo()
148 .expect("Supply chain QUBO should build successfully");
149 assert!(!var_map.is_empty());
150 }
151 #[test]
152 fn test_binary_vrp_wrapper() {
153 let distances = Array2::from_shape_vec(
154 (4, 4),
155 vec![
156 0.0, 10.0, 15.0, 20.0, 10.0, 0.0, 25.0, 30.0, 15.0, 25.0, 0.0, 35.0, 20.0, 30.0,
157 35.0, 0.0,
158 ],
159 )
160 .expect("Test distance matrix has valid shape");
161 let demands = Array1::from_vec(vec![0.0, 10.0, 15.0, 20.0]);
162 let optimizer = VehicleRoutingOptimizer::new(distances, 50.0, demands, 2)
163 .expect("Test VRP optimizer should be created with valid inputs");
164 let binary_vrp = BinaryVehicleRoutingProblem::new(optimizer);
165 assert_eq!(binary_vrp.num_variables(), 32);
166 let solution = binary_vrp.random_solution();
167 assert_eq!(solution.len(), 32);
168 let energy = binary_vrp.evaluate_binary(&solution);
169 assert!(energy.is_finite());
170 let routes = binary_vrp.decode_binary_solution(&solution);
171 assert!(routes.len() <= 2);
172 }
173 #[test]
174 fn test_create_benchmark_problems() {
175 let problems = create_benchmark_problems();
176 assert_eq!(problems.len(), 3);
177 for (i, problem) in problems.iter().enumerate() {
178 let solution = problem.random_solution();
179 let energy = problem.evaluate_binary(&solution);
180 assert!(energy.is_finite(), "Problem {i} should have finite energy");
181 let routes = problem.decode_binary_solution(&solution);
182 assert!(
183 routes.len() <= 3,
184 "Problem {i} should have at most 3 routes"
185 );
186 }
187 }
188}