1 // Copyright Michael Drexl 2005, 2006.
2 // Distributed under the Boost Software License, Version 1.0.
3 // (See accompanying file LICENSE_1_0.txt or copy at
4 // http://boost.org/LICENSE_1_0.txt)
5
6 // Example use of the resource-constrained shortest paths algorithm.
7 #include <boost/config.hpp>
8
9 #ifdef BOOST_MSVC
10 #pragma warning(disable : 4267)
11 #endif
12
13 #include <boost/graph/adjacency_list.hpp>
14
15 #include <boost/graph/r_c_shortest_paths.hpp>
16 #include <iostream>
17
18 using namespace boost;
19
20 struct SPPRC_Example_Graph_Vert_Prop
21 {
SPPRC_Example_Graph_Vert_PropSPPRC_Example_Graph_Vert_Prop22 SPPRC_Example_Graph_Vert_Prop(int n = 0, int e = 0, int l = 0)
23 : num(n), eat(e), lat(l)
24 {
25 }
26 int num;
27 // earliest arrival time
28 int eat;
29 // latest arrival time
30 int lat;
31 };
32
33 struct SPPRC_Example_Graph_Arc_Prop
34 {
SPPRC_Example_Graph_Arc_PropSPPRC_Example_Graph_Arc_Prop35 SPPRC_Example_Graph_Arc_Prop(int n = 0, int c = 0, int t = 0)
36 : num(n), cost(c), time(t)
37 {
38 }
39 int num;
40 // traversal cost
41 int cost;
42 // traversal time
43 int time;
44 };
45
46 typedef adjacency_list< vecS, vecS, directedS, SPPRC_Example_Graph_Vert_Prop,
47 SPPRC_Example_Graph_Arc_Prop >
48 SPPRC_Example_Graph;
49
50 // data structures for spp without resource constraints:
51 // ResourceContainer model
52 struct spp_no_rc_res_cont
53 {
spp_no_rc_res_contspp_no_rc_res_cont54 spp_no_rc_res_cont(int c = 0) : cost(c) {};
operator =spp_no_rc_res_cont55 spp_no_rc_res_cont& operator=(const spp_no_rc_res_cont& other)
56 {
57 if (this == &other)
58 return *this;
59 this->~spp_no_rc_res_cont();
60 new (this) spp_no_rc_res_cont(other);
61 return *this;
62 }
63 int cost;
64 };
65
operator ==(const spp_no_rc_res_cont & res_cont_1,const spp_no_rc_res_cont & res_cont_2)66 bool operator==(
67 const spp_no_rc_res_cont& res_cont_1, const spp_no_rc_res_cont& res_cont_2)
68 {
69 return (res_cont_1.cost == res_cont_2.cost);
70 }
71
operator <(const spp_no_rc_res_cont & res_cont_1,const spp_no_rc_res_cont & res_cont_2)72 bool operator<(
73 const spp_no_rc_res_cont& res_cont_1, const spp_no_rc_res_cont& res_cont_2)
74 {
75 return (res_cont_1.cost < res_cont_2.cost);
76 }
77
78 // ResourceExtensionFunction model
79 class ref_no_res_cont
80 {
81 public:
operator ()(const SPPRC_Example_Graph & g,spp_no_rc_res_cont & new_cont,const spp_no_rc_res_cont & old_cont,graph_traits<SPPRC_Example_Graph>::edge_descriptor ed) const82 inline bool operator()(const SPPRC_Example_Graph& g,
83 spp_no_rc_res_cont& new_cont, const spp_no_rc_res_cont& old_cont,
84 graph_traits< SPPRC_Example_Graph >::edge_descriptor ed) const
85 {
86 new_cont.cost = old_cont.cost + g[ed].cost;
87 return true;
88 }
89 };
90
91 // DominanceFunction model
92 class dominance_no_res_cont
93 {
94 public:
operator ()(const spp_no_rc_res_cont & res_cont_1,const spp_no_rc_res_cont & res_cont_2) const95 inline bool operator()(const spp_no_rc_res_cont& res_cont_1,
96 const spp_no_rc_res_cont& res_cont_2) const
97 {
98 // must be "<=" here!!!
99 // must NOT be "<"!!!
100 return res_cont_1.cost <= res_cont_2.cost;
101 // this is not a contradiction to the documentation
102 // the documentation says:
103 // "A label $l_1$ dominates a label $l_2$ if and only if both are
104 // resident at the same vertex, and if, for each resource, the resource
105 // consumption of $l_1$ is less than or equal to the resource
106 // consumption of $l_2$, and if there is at least one resource where
107 // $l_1$ has a lower resource consumption than $l_2$." one can think of
108 // a new label with a resource consumption equal to that of an old label
109 // as being dominated by that old label, because the new one will have a
110 // higher number and is created at a later point in time, so one can
111 // implicitly use the number or the creation time as a resource for
112 // tie-breaking
113 }
114 };
115 // end data structures for spp without resource constraints:
116
117 // data structures for shortest path problem with time windows (spptw)
118 // ResourceContainer model
119 struct spp_spptw_res_cont
120 {
spp_spptw_res_contspp_spptw_res_cont121 spp_spptw_res_cont(int c = 0, int t = 0) : cost(c), time(t) {}
operator =spp_spptw_res_cont122 spp_spptw_res_cont& operator=(const spp_spptw_res_cont& other)
123 {
124 if (this == &other)
125 return *this;
126 this->~spp_spptw_res_cont();
127 new (this) spp_spptw_res_cont(other);
128 return *this;
129 }
130 int cost;
131 int time;
132 };
133
operator ==(const spp_spptw_res_cont & res_cont_1,const spp_spptw_res_cont & res_cont_2)134 bool operator==(
135 const spp_spptw_res_cont& res_cont_1, const spp_spptw_res_cont& res_cont_2)
136 {
137 return (res_cont_1.cost == res_cont_2.cost
138 && res_cont_1.time == res_cont_2.time);
139 }
140
operator <(const spp_spptw_res_cont & res_cont_1,const spp_spptw_res_cont & res_cont_2)141 bool operator<(
142 const spp_spptw_res_cont& res_cont_1, const spp_spptw_res_cont& res_cont_2)
143 {
144 if (res_cont_1.cost > res_cont_2.cost)
145 return false;
146 if (res_cont_1.cost == res_cont_2.cost)
147 return res_cont_1.time < res_cont_2.time;
148 return true;
149 }
150
151 // ResourceExtensionFunction model
152 class ref_spptw
153 {
154 public:
operator ()(const SPPRC_Example_Graph & g,spp_spptw_res_cont & new_cont,const spp_spptw_res_cont & old_cont,graph_traits<SPPRC_Example_Graph>::edge_descriptor ed) const155 inline bool operator()(const SPPRC_Example_Graph& g,
156 spp_spptw_res_cont& new_cont, const spp_spptw_res_cont& old_cont,
157 graph_traits< SPPRC_Example_Graph >::edge_descriptor ed) const
158 {
159 const SPPRC_Example_Graph_Arc_Prop& arc_prop = get(edge_bundle, g)[ed];
160 const SPPRC_Example_Graph_Vert_Prop& vert_prop
161 = get(vertex_bundle, g)[target(ed, g)];
162 new_cont.cost = old_cont.cost + arc_prop.cost;
163 int& i_time = new_cont.time;
164 i_time = old_cont.time + arc_prop.time;
165 i_time < vert_prop.eat ? i_time = vert_prop.eat : 0;
166 return i_time <= vert_prop.lat ? true : false;
167 }
168 };
169
170 // DominanceFunction model
171 class dominance_spptw
172 {
173 public:
operator ()(const spp_spptw_res_cont & res_cont_1,const spp_spptw_res_cont & res_cont_2) const174 inline bool operator()(const spp_spptw_res_cont& res_cont_1,
175 const spp_spptw_res_cont& res_cont_2) const
176 {
177 // must be "<=" here!!!
178 // must NOT be "<"!!!
179 return res_cont_1.cost <= res_cont_2.cost
180 && res_cont_1.time <= res_cont_2.time;
181 // this is not a contradiction to the documentation
182 // the documentation says:
183 // "A label $l_1$ dominates a label $l_2$ if and only if both are
184 // resident at the same vertex, and if, for each resource, the resource
185 // consumption of $l_1$ is less than or equal to the resource
186 // consumption of $l_2$, and if there is at least one resource where
187 // $l_1$ has a lower resource consumption than $l_2$." one can think of
188 // a new label with a resource consumption equal to that of an old label
189 // as being dominated by that old label, because the new one will have a
190 // higher number and is created at a later point in time, so one can
191 // implicitly use the number or the creation time as a resource for
192 // tie-breaking
193 }
194 };
195 // end data structures for shortest path problem with time windows (spptw)
196
197 // example graph structure and cost from
198 // http://www.boost.org/libs/graph/example/dijkstra-example.cpp
199 enum nodes
200 {
201 A,
202 B,
203 C,
204 D,
205 E
206 };
207 char name[] = "ABCDE";
208
main()209 int main()
210 {
211 SPPRC_Example_Graph g;
212
213 add_vertex(SPPRC_Example_Graph_Vert_Prop(A, 0, 0), g);
214 add_vertex(SPPRC_Example_Graph_Vert_Prop(B, 5, 20), g);
215 add_vertex(SPPRC_Example_Graph_Vert_Prop(C, 6, 10), g);
216 add_vertex(SPPRC_Example_Graph_Vert_Prop(D, 3, 12), g);
217 add_vertex(SPPRC_Example_Graph_Vert_Prop(E, 0, 100), g);
218
219 add_edge(A, C, SPPRC_Example_Graph_Arc_Prop(0, 1, 5), g);
220 add_edge(B, B, SPPRC_Example_Graph_Arc_Prop(1, 2, 5), g);
221 add_edge(B, D, SPPRC_Example_Graph_Arc_Prop(2, 1, 2), g);
222 add_edge(B, E, SPPRC_Example_Graph_Arc_Prop(3, 2, 7), g);
223 add_edge(C, B, SPPRC_Example_Graph_Arc_Prop(4, 7, 3), g);
224 add_edge(C, D, SPPRC_Example_Graph_Arc_Prop(5, 3, 8), g);
225 add_edge(D, E, SPPRC_Example_Graph_Arc_Prop(6, 1, 3), g);
226 add_edge(E, A, SPPRC_Example_Graph_Arc_Prop(7, 1, 5), g);
227 add_edge(E, B, SPPRC_Example_Graph_Arc_Prop(8, 1, 4), g);
228
229 // the unique shortest path from A to E in the dijkstra-example.cpp is
230 // A -> C -> D -> E
231 // its length is 5
232 // the following code also yields this result
233
234 // with the above time windows, this path is infeasible
235 // now, there are two shortest paths that are also feasible with respect to
236 // the vertex time windows:
237 // A -> C -> B -> D -> E and
238 // A -> C -> B -> E
239 // however, the latter has a longer total travel time and is therefore not
240 // pareto-optimal, i.e., it is dominated by the former path
241 // therefore, the code below returns only the former path
242
243 // spp without resource constraints
244 graph_traits< SPPRC_Example_Graph >::vertex_descriptor s = A;
245 graph_traits< SPPRC_Example_Graph >::vertex_descriptor t = E;
246
247 std::vector<
248 std::vector< graph_traits< SPPRC_Example_Graph >::edge_descriptor > >
249 opt_solutions;
250 std::vector< spp_no_rc_res_cont > pareto_opt_rcs_no_rc;
251
252 r_c_shortest_paths(g, get(&SPPRC_Example_Graph_Vert_Prop::num, g),
253 get(&SPPRC_Example_Graph_Arc_Prop::num, g), s, t, opt_solutions,
254 pareto_opt_rcs_no_rc, spp_no_rc_res_cont(0), ref_no_res_cont(),
255 dominance_no_res_cont(),
256 std::allocator< r_c_shortest_paths_label< SPPRC_Example_Graph,
257 spp_no_rc_res_cont > >(),
258 default_r_c_shortest_paths_visitor());
259
260 std::cout << "SPP without resource constraints:" << std::endl;
261 std::cout << "Number of optimal solutions: ";
262 std::cout << static_cast< int >(opt_solutions.size()) << std::endl;
263 for (int i = 0; i < static_cast< int >(opt_solutions.size()); ++i)
264 {
265 std::cout << "The " << i << "th shortest path from A to E is: ";
266 std::cout << std::endl;
267 for (int j = static_cast< int >(opt_solutions[i].size()) - 1; j >= 0;
268 --j)
269 std::cout << name[source(opt_solutions[i][j], g)] << std::endl;
270 std::cout << "E" << std::endl;
271 std::cout << "Length: " << pareto_opt_rcs_no_rc[i].cost << std::endl;
272 }
273 std::cout << std::endl;
274
275 // spptw
276 std::vector<
277 std::vector< graph_traits< SPPRC_Example_Graph >::edge_descriptor > >
278 opt_solutions_spptw;
279 std::vector< spp_spptw_res_cont > pareto_opt_rcs_spptw;
280
281 r_c_shortest_paths(g, get(&SPPRC_Example_Graph_Vert_Prop::num, g),
282 get(&SPPRC_Example_Graph_Arc_Prop::num, g), s, t, opt_solutions_spptw,
283 pareto_opt_rcs_spptw, spp_spptw_res_cont(0, 0), ref_spptw(),
284 dominance_spptw(),
285 std::allocator< r_c_shortest_paths_label< SPPRC_Example_Graph,
286 spp_spptw_res_cont > >(),
287 default_r_c_shortest_paths_visitor());
288
289 std::cout << "SPP with time windows:" << std::endl;
290 std::cout << "Number of optimal solutions: ";
291 std::cout << static_cast< int >(opt_solutions.size()) << std::endl;
292 for (int i = 0; i < static_cast< int >(opt_solutions.size()); ++i)
293 {
294 std::cout << "The " << i << "th shortest path from A to E is: ";
295 std::cout << std::endl;
296 for (int j = static_cast< int >(opt_solutions_spptw[i].size()) - 1;
297 j >= 0; --j)
298 std::cout << name[source(opt_solutions_spptw[i][j], g)]
299 << std::endl;
300 std::cout << "E" << std::endl;
301 std::cout << "Length: " << pareto_opt_rcs_spptw[i].cost << std::endl;
302 std::cout << "Time: " << pareto_opt_rcs_spptw[i].time << std::endl;
303 }
304
305 // utility function check_r_c_path example
306 std::cout << std::endl;
307 bool b_is_a_path_at_all = false;
308 bool b_feasible = false;
309 bool b_correctly_extended = false;
310 spp_spptw_res_cont actual_final_resource_levels(0, 0);
311 graph_traits< SPPRC_Example_Graph >::edge_descriptor ed_last_extended_arc;
312 check_r_c_path(g, opt_solutions_spptw[0], spp_spptw_res_cont(0, 0), true,
313 pareto_opt_rcs_spptw[0], actual_final_resource_levels, ref_spptw(),
314 b_is_a_path_at_all, b_feasible, b_correctly_extended,
315 ed_last_extended_arc);
316 if (!b_is_a_path_at_all)
317 std::cout << "Not a path." << std::endl;
318 if (!b_feasible)
319 std::cout << "Not a feasible path." << std::endl;
320 if (!b_correctly_extended)
321 std::cout << "Not correctly extended." << std::endl;
322 if (b_is_a_path_at_all && b_feasible && b_correctly_extended)
323 {
324 std::cout << "Actual final resource levels:" << std::endl;
325 std::cout << "Length: " << actual_final_resource_levels.cost
326 << std::endl;
327 std::cout << "Time: " << actual_final_resource_levels.time << std::endl;
328 std::cout << "OK." << std::endl;
329 }
330
331 return 0;
332 }
333