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     cycle_begin = path[cycle_begin->GetNode()];
00355     Edge edge = this->job[prev][cycle_begin->GetNode()];
00356     edge.RemoveFlow(flow);
00357   } while (cycle_begin != cycle_end);
00358 }
00359 
00369 bool MCF1stPass::EliminateCycles(PathVector &path, NodeID origin_id, NodeID next_id)
00370 {
00371   static Path *invalid_path = new Path(INVALID_NODE, true);
00372   Path *at_next_pos = path[next_id];
00373 
00374   /* this node has already been searched */
00375   if (at_next_pos == invalid_path) return false;
00376 
00377   if (at_next_pos == NULL) {
00378     /* Summarize paths; add up the paths with the same source and next hop
00379      * in one path each. */
00380     PathList &paths = this->job[next_id].Paths();
00381     PathViaMap next_hops;
00382     for (PathList::iterator i = paths.begin(); i != paths.end(); ++i) {
00383       Path *new_child = *i;
00384       if (new_child->GetOrigin() == origin_id) {
00385         PathViaMap::iterator via_it = next_hops.find(new_child->GetNode());
00386         if (via_it == next_hops.end()) {
00387           next_hops[new_child->GetNode()] = new_child;
00388         } else {
00389           Path *child = via_it->second;
00390           uint new_flow = new_child->GetFlow();
00391           child->AddFlow(new_flow);
00392           new_child->ReduceFlow(new_flow);
00393         }
00394       }
00395     }
00396     bool found = false;
00397     /* Search the next hops for nodes we have already visited */
00398     for (PathViaMap::iterator via_it = next_hops.begin();
00399         via_it != next_hops.end(); ++via_it) {
00400       Path *child = via_it->second;
00401       if (child->GetFlow() > 0) {
00402         /* Push one child into the path vector and search this child's
00403          * children. */
00404         path[next_id] = child;
00405         found = this->EliminateCycles(path, origin_id, child->GetNode()) || found;
00406       }
00407     }
00408     /* All paths departing from this node have been searched. Mark as
00409      * resolved if no cycles found. If cycles were found further cycles
00410      * could be found in this branch, thus it has to be searched again next
00411      * time we spot it.
00412      */
00413     path[next_id] = found ? NULL : invalid_path;
00414     return found;
00415   }
00416 
00417   /* This node has already been visited => we have a cycle.
00418    * Backtrack to find the exact flow. */
00419   uint flow = this->FindCycleFlow(path, at_next_pos);
00420   if (flow > 0) {
00421     this->EliminateCycle(path, at_next_pos, flow);
00422     return true;
00423   }
00424 
00425   return false;
00426 }
00427 
00433 bool MCF1stPass::EliminateCycles()
00434 {
00435   bool cycles_found = false;
00436   uint size = this->job.Size();
00437   PathVector path(size, NULL);
00438   for (NodeID node = 0; node < size; ++node) {
00439     /* Starting at each node in the graph find all cycles involving this
00440      * node. */
00441     std::fill(path.begin(), path.end(), (Path *)NULL);
00442     cycles_found |= this->EliminateCycles(path, node, node);
00443   }
00444   return cycles_found;
00445 }
00446 
00451 MCF1stPass::MCF1stPass(LinkGraphJob &job) : MultiCommodityFlow(job)
00452 {
00453   PathVector paths;
00454   uint size = job.Size();
00455   uint accuracy = job.Settings().accuracy;
00456   bool more_loops;
00457 
00458   do {
00459     more_loops = false;
00460     for (NodeID source = 0; source < size; ++source) {
00461       /* First saturate the shortest paths. */
00462       this->Dijkstra<DistanceAnnotation, GraphEdgeIterator>(source, paths);
00463 
00464       for (NodeID dest = 0; dest < size; ++dest) {
00465         Edge edge = job[source][dest];
00466         if (edge.UnsatisfiedDemand() > 0) {
00467           Path *path = paths[dest];
00468           assert(path != NULL);
00469           /* Generally only allow paths that don't exceed the
00470            * available capacity. But if no demand has been assigned
00471            * yet, make an exception and allow any valid path *once*. */
00472           if (path->GetFreeCapacity() > 0 && this->PushFlow(edge, path,
00473               accuracy, this->max_saturation) > 0) {
00474             /* If a path has been found there is a chance we can
00475              * find more. */
00476             more_loops = more_loops || (edge.UnsatisfiedDemand() > 0);
00477           } else if (edge.UnsatisfiedDemand() == edge.Demand() &&
00478               path->GetFreeCapacity() > INT_MIN) {
00479             this->PushFlow(edge, path, accuracy, UINT_MAX);
00480           }
00481         }
00482       }
00483       this->CleanupPaths(source, paths);
00484     }
00485   } while (more_loops || this->EliminateCycles());
00486 }
00487 
00493 MCF2ndPass::MCF2ndPass(LinkGraphJob &job) : MultiCommodityFlow(job)
00494 {
00495   this->max_saturation = UINT_MAX; // disable artificial cap on saturation
00496   PathVector paths;
00497   uint size = job.Size();
00498   uint accuracy = job.Settings().accuracy;
00499   bool demand_left = true;
00500   while (demand_left) {
00501     demand_left = false;
00502     for (NodeID source = 0; source < size; ++source) {
00503       this->Dijkstra<CapacityAnnotation, FlowEdgeIterator>(source, paths);
00504       for (NodeID dest = 0; dest < size; ++dest) {
00505         Edge edge = this->job[source][dest];
00506         Path *path = paths[dest];
00507         if (edge.UnsatisfiedDemand() > 0 && path->GetFreeCapacity() > INT_MIN) {
00508           this->PushFlow(edge, path, accuracy, UINT_MAX);
00509           if (edge.UnsatisfiedDemand() > 0) demand_left = true;
00510         }
00511       }
00512       this->CleanupPaths(source, paths);
00513     }
00514   }
00515 }
00516 
00528 template <typename T>
00529 bool Greater(T x_anno, T y_anno, NodeID x, NodeID y)
00530 {
00531   if (x_anno > y_anno) return true;
00532   if (x_anno < y_anno) return false;
00533   return x > y;
00534 }
00535 
00542 bool CapacityAnnotation::Comparator::operator()(const CapacityAnnotation *x,
00543     const CapacityAnnotation *y) const
00544 {
00545   return x != y && Greater<int>(x->GetAnnotation(), y->GetAnnotation(),
00546       x->GetNode(), y->GetNode());
00547 }
00548 
00555 bool DistanceAnnotation::Comparator::operator()(const DistanceAnnotation *x,
00556     const DistanceAnnotation *y) const
00557 {
00558   return x != y && !Greater<uint>(x->GetAnnotation(), y->GetAnnotation(),
00559       x->GetNode(), y->GetNode());
00560 }