# mcf.cpp

Go to the documentation of this file.

    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   /* If any of the paths is disconnected, the other one is better. If both
    00185    * are disconnected, this path is better.*/
    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     /* If both paths have capacity left, compare their distances.
    00194      * If the other path has capacity left and this one hasn't, the
    00195      * other one's better (thus, return true). */
    00196     return this->free_capacity > 0 ? (base->distance + dist < this->distance) : true;
    00197   } else {
    00198     /* If the other path doesn't have capacity left, but this one has,
    00199      * the other one is worse (thus, return false).
    00200      * If both paths are out of capacity, do the regular distance
    00201      * comparison. */
    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     /* If the capacities are the same and the other path isn't disconnected
    00222      * choose the shorter path. */
    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; // Not a real edge but a consumption sign.
    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       /* punish in-between stops a little */
    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   /* this node has already been searched */
    00385   if (at_next_pos == invalid_path) return false;
    00386
    00387   if (at_next_pos == NULL) {
    00388     /* Summarize paths; add up the paths with the same source and next hop
    00389      * in one path each. */
    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           /* We might hit end() with with the ++ here and skip the
    00407            * newly push_back'ed path. That's good as the flow of that
    00408            * path is 0 anyway. */
    00409           paths.erase(i++);
    00410           paths.push_back(new_child);
    00411         }
    00412       } else {
    00413         ++i;
    00414       }
    00415     }
    00416     bool found = false;
    00417     /* Search the next hops for nodes we have already visited */
    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         /* Push one child into the path vector and search this child's
    00423          * children. */
    00424         path[next_id] = child;
    00425         found = this->EliminateCycles(path, origin_id, child->GetNode()) || found;
    00426       }
    00427     }
    00428     /* All paths departing from this node have been searched. Mark as
    00429      * resolved if no cycles found. If cycles were found further cycles
    00430      * could be found in this branch, thus it has to be searched again next
    00431      * time we spot it.
    00432      */
    00433     path[next_id] = found ? NULL : invalid_path;
    00434     return found;
    00435   }
    00436
    00437   /* This node has already been visited => we have a cycle.
    00438    * Backtrack to find the exact flow. */
    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     /* Starting at each node in the graph find all cycles involving this
    00460      * node. */
    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       /* First saturate the shortest paths. */
    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           /* Generally only allow paths that don't exceed the
    00490            * available capacity. But if no demand has been assigned
    00491            * yet, make an exception and allow any valid path *once*. */
    00492           if (path->GetFreeCapacity() > 0 && this->PushFlow(edge, path,
    00493               accuracy, this->max_saturation) > 0) {
    00494             /* If a path has been found there is a chance we can
    00495              * find more. */
    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; // disable artificial cap on saturation
    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 }