Ticket #11723: boost_bug.cpp

File boost_bug.cpp, 7.5 KB (added by a.santini@…, 7 years ago)

boost_bug.cpp

Line 
1#include <iostream>
2#include <fstream>
3#include <sstream>
4#include <unordered_map>
5
6#include <boost/graph/graph_traits.hpp>
7#include <boost/graph/adjacency_list.hpp>
8#include <boost/graph/r_c_shortest_paths.hpp>
9#include <boost/utility/result_of.hpp>
10
11static constexpr double EPS = 0.00001;
12
13struct VertexInfo {
14 unsigned int id;
15 unsigned int pickup; // Quantity to be picked up (> 0 iff delivery == 0)
16 unsigned int delivery; // Quantity to be delivered (> 0 iff pickup == 0)
17 double dual; // Vertex dual value from a Linear Program
18 double penalty; // Penalty avoided if visiting this vertex
19};
20
21struct EdgeInfo {
22 unsigned int id;
23 unsigned int source_id;
24 unsigned int target_id;
25 double cost; // Cost of going from source to target
26};
27
28using namespace boost;
29
30using Graph = adjacency_list<listS, listS, bidirectionalS, VertexInfo, EdgeInfo>;
31using Vertex = Graph::vertex_descriptor;
32using Edge = Graph::edge_descriptor;
33using Path = std::vector<Edge>;
34
35struct GraphForLabelling {
36 const Graph graph;
37 const Vertex source;
38 const Vertex sink;
39};
40
41struct Label {
42 unsigned int pickup; // Quantity that can be picked up after the current node
43 unsigned int delivery; // Quantity that can be delivered after the current node
44 double cost; // Cost of the partial path
45};
46
47inline bool operator<(const Label& lhs, const Label& rhs) {
48 return ( lhs.pickup >= rhs.pickup && // LHS can pickup more
49 lhs.delivery >= rhs.delivery && // LHS can deliver more
50 rhs.cost - lhs.cost > EPS && // LHS costs less
51 // And at least one of the first two inequalities is strict
52 (lhs.pickup > rhs.pickup || lhs.delivery > rhs.delivery)
53 );
54}
55
56inline bool operator==(const Label& lhs, const Label& rhs) {
57 return ( lhs.pickup == rhs.pickup &&
58 lhs.delivery == rhs.delivery &&
59 std::abs(lhs.cost - rhs.cost) < EPS
60 );
61}
62
63class LabelExtender {
64public:
65 bool operator()(const Graph& graph, Label& new_label, const Label& label, const Edge& edge) const {
66 auto destination = graph[target(edge, graph)];
67
68 new_label.pickup = label.pickup - destination.pickup;
69 new_label.delivery = std::min(label.delivery - destination.delivery, label.pickup - destination.pickup);
70 new_label.cost = label.cost + graph[edge].cost - destination.penalty - destination.dual;
71
72 return (new_label.pickup >= destination.pickup && new_label.delivery >= destination.delivery);
73 }
74};
75
76class LabelDominance {
77public:
78 inline bool operator()(const Label& lhs, const Label& rhs) const {
79 return (lhs < rhs || lhs == rhs);
80 }
81};
82
83class VertexIdFnt {
84 using result_type = unsigned int;
85
86 const Graph& g;
87
88public:
89 explicit VertexIdFnt(const Graph& g) : g{g} {}
90
91 result_type operator()(const Vertex& v) const { return g[v].id; }
92};
93
94class EdgeIdFnt {
95 using result_type = unsigned int;
96
97 const Graph& g;
98
99public:
100 explicit EdgeIdFnt(const Graph& g) : g{g} {}
101
102 result_type operator()(const Edge& e) const { return g[e].id; }
103};
104
105template<typename Fun, typename Arg>
106class FntPropertyMap {
107 using value_type = typename boost::result_of<Fun(Arg)>::type;
108
109 const Fun& f;
110
111public:
112 explicit FntPropertyMap(const Fun& f) : f{f} {}
113 friend value_type get(const FntPropertyMap& pm, const Arg& arg) { return pm.f(arg); }
114 value_type operator[](const Arg& arg) const { return f(arg); }
115};
116
117namespace boost{
118 template<typename Fun, typename Arg> struct property_traits<FntPropertyMap<Fun, Arg>> {
119 using value_type = typename boost::result_of<Fun(Arg)>::type;
120 using reference = value_type;
121 using key_type = Arg;
122 using category = readable_property_map_tag;
123 };
124}
125
126template<typename Arg, typename Fun> FntPropertyMap<Fun, Arg> make_property_map(const Fun& f) {
127 return FntPropertyMap<Fun, Arg>(f);
128}
129
130GraphForLabelling read_graph() {
131 std::ifstream gfile;
132 std::string line;
133
134 Graph graph{};
135 Vertex source{}, sink{};
136 unsigned int source_id = 0u, sink_id = 0u;
137
138 gfile.open("graph.txt");
139
140 /****** Read number of vertices ******/
141
142 unsigned int num_vertices;
143
144 if(std::getline(gfile, line)) {
145 std::stringstream ss(line);
146 ss >> num_vertices;
147 std::cout << "Reading a graph with " << num_vertices << " vertices." << std::endl;
148 } else {
149 std::cerr << "Can't read first line of the file!" << std::endl;
150 }
151
152 /****** Read vertices ******/
153
154 using VertexList = std::unordered_map<unsigned int, Vertex>;
155
156 VertexList vl{};
157 unsigned int id, pickup, delivery;
158 double dual, penalty;
159 std::string vertex_type;
160 std::stringstream ss("");
161
162 for(auto line_counter = 0u; line_counter < num_vertices; ++line_counter) {
163 std::getline(gfile, line);
164
165 ss.str(line);
166 ss >> id >> vertex_type >> pickup >> delivery >> dual >> penalty;
167
168 if(vertex_type == "src") {
169 source = add_vertex(graph);
170 source_id = id;
171 graph[source] = VertexInfo{id, pickup, delivery, dual, penalty};
172 } else if(vertex_type == "snk") {
173 sink = add_vertex(graph);
174 sink_id = id;
175 graph[sink] = VertexInfo{id, pickup, delivery, dual, penalty};
176 } else {
177 assert(vertex_type == "reg");
178 vl.insert({id, add_vertex(graph)});
179 graph[vl[id]] = VertexInfo{id, pickup, delivery, dual, penalty};
180 }
181
182 ss.str(std::string());
183 ss.clear();
184 }
185
186 /****** Read edges ******/
187 Edge e;
188 unsigned int edge_source_id, edge_target_id, edge_n = 0u;
189 double cost;
190
191 while(std::getline(gfile,line)) {
192 ss.str(line);
193 ss >> id >> edge_source_id >> edge_target_id >> cost;
194
195 assert(edge_source_id != sink_id && edge_target_id != source_id);
196
197 if(edge_source_id == source_id) {
198 e = add_edge(source, vl[edge_target_id], graph).first;
199 } else if(edge_target_id == sink_id) {
200 e = add_edge(vl[edge_source_id], sink, graph).first;
201 } else {
202 e = add_edge(vl[edge_source_id], vl[edge_target_id], graph).first;
203 }
204
205 graph[e] = EdgeInfo{id, edge_source_id, edge_target_id, cost};
206
207 ss.str(std::string());
208 ss.clear();
209 ++edge_n;
210 }
211
212 std::cout << "Created a graph with " << edge_n << " edges." << std::endl;
213
214 return GraphForLabelling{graph, source, sink};
215}
216
217void do_labelling(GraphForLabelling gfl, unsigned int capacity) {
218 std::vector<Path> optimal_paths{};
219 std::vector<Label> optimal_labels{};
220 VertexIdFnt vi{gfl.graph};
221 EdgeIdFnt ei{gfl.graph};
222
223 std::cout << "Launching r_c_shortest_paths ..." << std::endl;
224
225 r_c_shortest_paths(
226 gfl.graph,
227 make_property_map<Vertex>(vi),
228 make_property_map<Edge>(ei),
229 gfl.source,
230 gfl.sink,
231 optimal_paths,
232 optimal_labels,
233 Label{capacity, capacity, 0.0},
234 LabelExtender{},
235 LabelDominance{},
236 std::allocator<r_c_shortest_paths_label<Graph, Label>>{},
237 default_r_c_shortest_paths_visitor{}
238 );
239
240 std::cout << "Done: r_c_shortest_paths completed successfully" << std::endl;
241}
242
243int main() {
244 auto graph_for_labelling = read_graph();
245
246 do_labelling(graph_for_labelling, 450u);
247
248 return 0;
249}