• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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