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 |
|
---|
11 | static constexpr double EPS = 0.00001;
|
---|
12 |
|
---|
13 | struct 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 |
|
---|
21 | struct 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 |
|
---|
28 | using namespace boost;
|
---|
29 |
|
---|
30 | using Graph = adjacency_list<listS, listS, bidirectionalS, VertexInfo, EdgeInfo>;
|
---|
31 | using Vertex = Graph::vertex_descriptor;
|
---|
32 | using Edge = Graph::edge_descriptor;
|
---|
33 | using Path = std::vector<Edge>;
|
---|
34 |
|
---|
35 | struct GraphForLabelling {
|
---|
36 | const Graph graph;
|
---|
37 | const Vertex source;
|
---|
38 | const Vertex sink;
|
---|
39 | };
|
---|
40 |
|
---|
41 | struct 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 |
|
---|
47 | inline 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 |
|
---|
56 | inline 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 |
|
---|
63 | class LabelExtender {
|
---|
64 | public:
|
---|
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 |
|
---|
76 | class LabelDominance {
|
---|
77 | public:
|
---|
78 | inline bool operator()(const Label& lhs, const Label& rhs) const {
|
---|
79 | return (lhs < rhs || lhs == rhs);
|
---|
80 | }
|
---|
81 | };
|
---|
82 |
|
---|
83 | class VertexIdFnt {
|
---|
84 | using result_type = unsigned int;
|
---|
85 |
|
---|
86 | const Graph& g;
|
---|
87 |
|
---|
88 | public:
|
---|
89 | explicit VertexIdFnt(const Graph& g) : g{g} {}
|
---|
90 |
|
---|
91 | result_type operator()(const Vertex& v) const { return g[v].id; }
|
---|
92 | };
|
---|
93 |
|
---|
94 | class EdgeIdFnt {
|
---|
95 | using result_type = unsigned int;
|
---|
96 |
|
---|
97 | const Graph& g;
|
---|
98 |
|
---|
99 | public:
|
---|
100 | explicit EdgeIdFnt(const Graph& g) : g{g} {}
|
---|
101 |
|
---|
102 | result_type operator()(const Edge& e) const { return g[e].id; }
|
---|
103 | };
|
---|
104 |
|
---|
105 | template<typename Fun, typename Arg>
|
---|
106 | class FntPropertyMap {
|
---|
107 | using value_type = typename boost::result_of<Fun(Arg)>::type;
|
---|
108 |
|
---|
109 | const Fun& f;
|
---|
110 |
|
---|
111 | public:
|
---|
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 |
|
---|
117 | namespace 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 |
|
---|
126 | template<typename Arg, typename Fun> FntPropertyMap<Fun, Arg> make_property_map(const Fun& f) {
|
---|
127 | return FntPropertyMap<Fun, Arg>(f);
|
---|
128 | }
|
---|
129 |
|
---|
130 | GraphForLabelling 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 |
|
---|
217 | void 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 |
|
---|
243 | int main() {
|
---|
244 | auto graph_for_labelling = read_graph();
|
---|
245 |
|
---|
246 | do_labelling(graph_for_labelling, 450u);
|
---|
247 |
|
---|
248 | return 0;
|
---|
249 | }
|
---|