| 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 | }
|
|---|