00001
00003 #include "../stdafx.h"
00004 #include "../core/math_func.hpp"
00005 #include "mcf.h"
00006 #include <set>
00007
00008 typedef std::map<NodeID, Path *> PathViaMap;
00009
00015 class DistanceAnnotation : public Path {
00016 public:
00017
00023 DistanceAnnotation(NodeID n, bool source = false) : Path(n, source) {}
00024
00025 bool IsBetter(const DistanceAnnotation *base, uint cap, int free_cap, uint dist) const;
00026
00031 inline uint GetAnnotation() const { return this->distance; }
00032
00036 struct Comparator {
00037 bool operator()(const DistanceAnnotation *x, const DistanceAnnotation *y) const;
00038 };
00039 };
00040
00047 class CapacityAnnotation : public Path {
00048 public:
00049
00055 CapacityAnnotation(NodeID n, bool source = false) : Path(n, source) {}
00056
00057 bool IsBetter(const CapacityAnnotation *base, uint cap, int free_cap, uint dist) const;
00058
00063 inline int GetAnnotation() const { return this->GetCapacityRatio(); }
00064
00068 struct Comparator {
00069 bool operator()(const CapacityAnnotation *x, const CapacityAnnotation *y) const;
00070 };
00071 };
00072
00077 class GraphEdgeIterator {
00078 private:
00079 LinkGraphJob &job;
00080 EdgeIterator i;
00081 EdgeIterator end;
00082
00083 public:
00084
00089 GraphEdgeIterator(LinkGraphJob &job) : job(job),
00090 i(NULL, NULL, INVALID_NODE), end(NULL, NULL, INVALID_NODE)
00091 {}
00092
00098 void SetNode(NodeID source, NodeID node)
00099 {
00100 this->i = this->job[node].Begin();
00101 this->end = this->job[node].End();
00102 }
00103
00108 NodeID Next()
00109 {
00110 return this->i != this->end ? (this->i++)->first : INVALID_NODE;
00111 }
00112 };
00113
00117 class FlowEdgeIterator {
00118 private:
00119 LinkGraphJob &job;
00120
00122 std::map<StationID, NodeID> station_to_node;
00123
00125 FlowStat::SharesMap::const_iterator it;
00126
00128 FlowStat::SharesMap::const_iterator end;
00129 public:
00130
00135 FlowEdgeIterator(LinkGraphJob &job) : job(job)
00136 {
00137 for (NodeID i = 0; i < job.Size(); ++i) {
00138 this->station_to_node[job[i].Station()] = i;
00139 }
00140 }
00141
00147 void SetNode(NodeID source, NodeID node)
00148 {
00149 static const FlowStat::SharesMap empty;
00150 const FlowStatMap &flows = this->job[node].Flows();
00151 FlowStatMap::const_iterator it = flows.find(this->job[source].Station());
00152 if (it != flows.end()) {
00153 this->it = it->second.GetShares()->begin();
00154 this->end = it->second.GetShares()->end();
00155 } else {
00156 this->it = empty.begin();
00157 this->end = empty.end();
00158 }
00159 }
00160
00165 NodeID Next()
00166 {
00167 if (this->it == this->end) return INVALID_NODE;
00168 return this->station_to_node[(this->it++)->second];
00169 }
00170 };
00171
00181 bool DistanceAnnotation::IsBetter(const DistanceAnnotation *base, uint cap,
00182 int free_cap, uint dist) const
00183 {
00184
00185
00186 if (base->distance == UINT_MAX) {
00187 return false;
00188 } else if (this->distance == UINT_MAX) {
00189 return true;
00190 }
00191
00192 if (free_cap > 0 && base->free_capacity > 0) {
00193
00194
00195
00196 return this->free_capacity > 0 ? (base->distance + dist < this->distance) : true;
00197 } else {
00198
00199
00200
00201
00202 return this->free_capacity > 0 ? false : (base->distance + dist < this->distance);
00203 }
00204 }
00205
00215 bool CapacityAnnotation::IsBetter(const CapacityAnnotation *base, uint cap,
00216 int free_cap, uint dist) const
00217 {
00218 int min_cap = Path::GetCapacityRatio(min(base->free_capacity, free_cap), min(base->capacity, cap));
00219 int this_cap = this->GetCapacityRatio();
00220 if (min_cap == this_cap) {
00221
00222
00223 return base->distance == UINT_MAX ? false : (base->distance + dist < this->distance);
00224 } else {
00225 return min_cap > this_cap;
00226 }
00227 }
00228
00238 template<class Tannotation, class Tedge_iterator>
00239 void MultiCommodityFlow::Dijkstra(NodeID source_node, PathVector &paths)
00240 {
00241 typedef std::set<Tannotation *, typename Tannotation::Comparator> AnnoSet;
00242 Tedge_iterator iter(this->job);
00243 uint size = this->job.Size();
00244 AnnoSet annos;
00245 paths.resize(size, NULL);
00246 for (NodeID node = 0; node < size; ++node) {
00247 Tannotation *anno = new Tannotation(node, node == source_node);
00248 annos.insert(anno);
00249 paths[node] = anno;
00250 }
00251 while (!annos.empty()) {
00252 typename AnnoSet::iterator i = annos.begin();
00253 Tannotation *source = *i;
00254 annos.erase(i);
00255 NodeID from = source->GetNode();
00256 iter.SetNode(source_node, from);
00257 for (NodeID to = iter.Next(); to != INVALID_NODE; to = iter.Next()) {
00258 if (to == from) continue;
00259 Edge edge = this->job[from][to];
00260 assert(edge.Distance() < UINT_MAX);
00261 uint capacity = edge.Capacity();
00262 if (this->max_saturation != UINT_MAX) {
00263 capacity *= this->max_saturation;
00264 capacity /= 100;
00265 if (capacity == 0) capacity = 1;
00266 }
00267
00268 uint distance = edge.Distance() + 1;
00269 Tannotation *dest = static_cast<Tannotation *>(paths[to]);
00270 if (dest->IsBetter(source, capacity, capacity - edge.Flow(), distance)) {
00271 annos.erase(dest);
00272 dest->Fork(source, capacity, capacity - edge.Flow(), distance);
00273 annos.insert(dest);
00274 }
00275 }
00276 }
00277 }
00278
00284 void MultiCommodityFlow::CleanupPaths(NodeID source_id, PathVector &paths)
00285 {
00286 Path *source = paths[source_id];
00287 paths[source_id] = NULL;
00288 for (PathVector::iterator i = paths.begin(); i != paths.end(); ++i) {
00289 Path *path = *i;
00290 if (path == NULL) continue;
00291 if (path->GetParent() == source) path->Detach();
00292 while (path != source && path != NULL && path->GetFlow() == 0) {
00293 Path *parent = path->GetParent();
00294 path->Detach();
00295 if (path->GetNumChildren() == 0) {
00296 paths[path->GetNode()] = NULL;
00297 delete path;
00298 }
00299 path = parent;
00300 }
00301 }
00302 delete source;
00303 paths.clear();
00304 }
00305
00315 uint MultiCommodityFlow::PushFlow(Edge &edge, Path *path, uint accuracy,
00316 uint max_saturation)
00317 {
00318 assert(edge.UnsatisfiedDemand() > 0);
00319 uint flow = Clamp(edge.Demand() / accuracy, 1, edge.UnsatisfiedDemand());
00320 flow = path->AddFlow(flow, this->job, max_saturation);
00321 edge.SatisfyDemand(flow);
00322 return flow;
00323 }
00324
00331 uint MCF1stPass::FindCycleFlow(const PathVector &path, const Path *cycle_begin)
00332 {
00333 uint flow = UINT_MAX;
00334 const Path *cycle_end = cycle_begin;
00335 do {
00336 flow = min(flow, cycle_begin->GetFlow());
00337 cycle_begin = path[cycle_begin->GetNode()];
00338 } while (cycle_begin != cycle_end);
00339 return flow;
00340 }
00341
00348 void MCF1stPass::EliminateCycle(PathVector &path, Path *cycle_begin, uint flow)
00349 {
00350 Path *cycle_end = cycle_begin;
00351 do {
00352 NodeID prev = cycle_begin->GetNode();
00353 cycle_begin->ReduceFlow(flow);
00354 if (cycle_begin->GetFlow() == 0) {
00355 PathList &node_paths = this->job[cycle_begin->GetParent()->GetNode()].Paths();
00356 for (PathList::iterator i = node_paths.begin(); i != node_paths.end(); ++i) {
00357 if (*i == cycle_begin) {
00358 node_paths.erase(i);
00359 node_paths.push_back(cycle_begin);
00360 break;
00361 }
00362 }
00363 }
00364 cycle_begin = path[prev];
00365 Edge edge = this->job[prev][cycle_begin->GetNode()];
00366 edge.RemoveFlow(flow);
00367 } while (cycle_begin != cycle_end);
00368 }
00369
00379 bool MCF1stPass::EliminateCycles(PathVector &path, NodeID origin_id, NodeID next_id)
00380 {
00381 static Path *invalid_path = new Path(INVALID_NODE, true);
00382 Path *at_next_pos = path[next_id];
00383
00384
00385 if (at_next_pos == invalid_path) return false;
00386
00387 if (at_next_pos == NULL) {
00388
00389
00390 PathList &paths = this->job[next_id].Paths();
00391 PathViaMap next_hops;
00392 for (PathList::iterator i = paths.begin(); i != paths.end();) {
00393 Path *new_child = *i;
00394 uint new_flow = new_child->GetFlow();
00395 if (new_flow == 0) break;
00396 if (new_child->GetOrigin() == origin_id) {
00397 PathViaMap::iterator via_it = next_hops.find(new_child->GetNode());
00398 if (via_it == next_hops.end()) {
00399 next_hops[new_child->GetNode()] = new_child;
00400 ++i;
00401 } else {
00402 Path *child = via_it->second;
00403 child->AddFlow(new_flow);
00404 new_child->ReduceFlow(new_flow);
00405
00406
00407
00408
00409 paths.erase(i++);
00410 paths.push_back(new_child);
00411 }
00412 } else {
00413 ++i;
00414 }
00415 }
00416 bool found = false;
00417
00418 for (PathViaMap::iterator via_it = next_hops.begin();
00419 via_it != next_hops.end(); ++via_it) {
00420 Path *child = via_it->second;
00421 if (child->GetFlow() > 0) {
00422
00423
00424 path[next_id] = child;
00425 found = this->EliminateCycles(path, origin_id, child->GetNode()) || found;
00426 }
00427 }
00428
00429
00430
00431
00432
00433 path[next_id] = found ? NULL : invalid_path;
00434 return found;
00435 }
00436
00437
00438
00439 uint flow = this->FindCycleFlow(path, at_next_pos);
00440 if (flow > 0) {
00441 this->EliminateCycle(path, at_next_pos, flow);
00442 return true;
00443 }
00444
00445 return false;
00446 }
00447
00453 bool MCF1stPass::EliminateCycles()
00454 {
00455 bool cycles_found = false;
00456 uint size = this->job.Size();
00457 PathVector path(size, NULL);
00458 for (NodeID node = 0; node < size; ++node) {
00459
00460
00461 std::fill(path.begin(), path.end(), (Path *)NULL);
00462 cycles_found |= this->EliminateCycles(path, node, node);
00463 }
00464 return cycles_found;
00465 }
00466
00471 MCF1stPass::MCF1stPass(LinkGraphJob &job) : MultiCommodityFlow(job)
00472 {
00473 PathVector paths;
00474 uint size = job.Size();
00475 uint accuracy = job.Settings().accuracy;
00476 bool more_loops;
00477
00478 do {
00479 more_loops = false;
00480 for (NodeID source = 0; source < size; ++source) {
00481
00482 this->Dijkstra<DistanceAnnotation, GraphEdgeIterator>(source, paths);
00483
00484 for (NodeID dest = 0; dest < size; ++dest) {
00485 Edge edge = job[source][dest];
00486 if (edge.UnsatisfiedDemand() > 0) {
00487 Path *path = paths[dest];
00488 assert(path != NULL);
00489
00490
00491
00492 if (path->GetFreeCapacity() > 0 && this->PushFlow(edge, path,
00493 accuracy, this->max_saturation) > 0) {
00494
00495
00496 more_loops = more_loops || (edge.UnsatisfiedDemand() > 0);
00497 } else if (edge.UnsatisfiedDemand() == edge.Demand() &&
00498 path->GetFreeCapacity() > INT_MIN) {
00499 this->PushFlow(edge, path, accuracy, UINT_MAX);
00500 }
00501 }
00502 }
00503 this->CleanupPaths(source, paths);
00504 }
00505 } while (more_loops || this->EliminateCycles());
00506 }
00507
00513 MCF2ndPass::MCF2ndPass(LinkGraphJob &job) : MultiCommodityFlow(job)
00514 {
00515 this->max_saturation = UINT_MAX;
00516 PathVector paths;
00517 uint size = job.Size();
00518 uint accuracy = job.Settings().accuracy;
00519 bool demand_left = true;
00520 while (demand_left) {
00521 demand_left = false;
00522 for (NodeID source = 0; source < size; ++source) {
00523 this->Dijkstra<CapacityAnnotation, FlowEdgeIterator>(source, paths);
00524 for (NodeID dest = 0; dest < size; ++dest) {
00525 Edge edge = this->job[source][dest];
00526 Path *path = paths[dest];
00527 if (edge.UnsatisfiedDemand() > 0 && path->GetFreeCapacity() > INT_MIN) {
00528 this->PushFlow(edge, path, accuracy, UINT_MAX);
00529 if (edge.UnsatisfiedDemand() > 0) demand_left = true;
00530 }
00531 }
00532 this->CleanupPaths(source, paths);
00533 }
00534 }
00535 }
00536
00548 template <typename T>
00549 bool Greater(T x_anno, T y_anno, NodeID x, NodeID y)
00550 {
00551 if (x_anno > y_anno) return true;
00552 if (x_anno < y_anno) return false;
00553 return x > y;
00554 }
00555
00562 bool CapacityAnnotation::Comparator::operator()(const CapacityAnnotation *x,
00563 const CapacityAnnotation *y) const
00564 {
00565 return x != y && Greater<int>(x->GetAnnotation(), y->GetAnnotation(),
00566 x->GetNode(), y->GetNode());
00567 }
00568
00575 bool DistanceAnnotation::Comparator::operator()(const DistanceAnnotation *x,
00576 const DistanceAnnotation *y) const
00577 {
00578 return x != y && !Greater<uint>(x->GetAnnotation(), y->GetAnnotation(),
00579 x->GetNode(), y->GetNode());
00580 }