# 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
    00007 typedef std::map<NodeID, Path *> PathViaMap;
    00008
    00014 class DistanceAnnotation : public Path {
    00015 public:
    00016
    00022   DistanceAnnotation(NodeID n, bool source = false) : Path(n, source) {}
    00023
    00024   bool IsBetter(const DistanceAnnotation *base, uint cap, int free_cap, uint dist) const;
    00025
    00030   inline uint GetAnnotation() const { return this->distance; }
    00031
    00035   struct Comparator {
    00036     bool operator()(const DistanceAnnotation *x, const DistanceAnnotation *y) const;
    00037   };
    00038 };
    00039
    00046 class CapacityAnnotation : public Path {
    00047 public:
    00048
    00054   CapacityAnnotation(NodeID n, bool source = false) : Path(n, source) {}
    00055
    00056   bool IsBetter(const CapacityAnnotation *base, uint cap, int free_cap, uint dist) const;
    00057
    00062   inline int GetAnnotation() const { return this->GetCapacityRatio(); }
    00063
    00067   struct Comparator {
    00068     bool operator()(const CapacityAnnotation *x, const CapacityAnnotation *y) const;
    00069   };
    00070 };
    00071
    00076 class GraphEdgeIterator {
    00077 private:
    00078   LinkGraphJob &job;
    00079   EdgeIterator i;
    00080   EdgeIterator end;
    00081
    00082 public:
    00083
    00088   GraphEdgeIterator(LinkGraphJob &job) : job(job),
    00089     i(NULL, NULL, INVALID_NODE), end(NULL, NULL, INVALID_NODE)
    00090   {}
    00091
    00097   void SetNode(NodeID source, NodeID node)
    00098   {
    00099     this->i = this->job[node].Begin();
    00100     this->end = this->job[node].End();
    00101   }
    00102
    00107   NodeID Next()
    00108   {
    00109     return this->i != this->end ? (this->i++)->first : INVALID_NODE;
    00110   }
    00111 };
    00112
    00116 class FlowEdgeIterator {
    00117 private:
    00118   LinkGraphJob &job;
    00119
    00121   std::map<StationID, NodeID> station_to_node;
    00122
    00124   FlowStat::SharesMap::const_iterator it;
    00125
    00127   FlowStat::SharesMap::const_iterator end;
    00128 public:
    00129
    00134   FlowEdgeIterator(LinkGraphJob &job) : job(job)
    00135   {
    00136     for (NodeID i = 0; i < job.Size(); ++i) {
    00137       this->station_to_node[job[i].Station()] = i;
    00138     }
    00139   }
    00140
    00146   void SetNode(NodeID source, NodeID node)
    00147   {
    00148     static const FlowStat::SharesMap empty;
    00149     const FlowStatMap &flows = this->job[node].Flows();
    00150     FlowStatMap::const_iterator it = flows.find(this->job[source].Station());
    00151     if (it != flows.end()) {
    00152       this->it = it->second.GetShares()->begin();
    00153       this->end = it->second.GetShares()->end();
    00154     } else {
    00155       this->it = empty.begin();
    00156       this->end = empty.end();
    00157     }
    00158   }
    00159
    00164   NodeID Next()
    00165   {
    00166     if (this->it == this->end) return INVALID_NODE;
    00167     return this->station_to_node[(this->it++)->second];
    00168   }
    00169 };
    00170
    00180 bool DistanceAnnotation::IsBetter(const DistanceAnnotation *base, uint cap,
    00181     int free_cap, uint dist) const
    00182 {
    00183   /* If any of the paths is disconnected, the other one is better. If both
    00184    * are disconnected, this path is better.*/
    00185   if (base->distance == UINT_MAX) {
    00186     return false;
    00187   } else if (this->distance == UINT_MAX) {
    00188     return true;
    00189   }
    00190
    00191   if (free_cap > 0 && base->free_capacity > 0) {
    00192     /* If both paths have capacity left, compare their distances.
    00193      * If the other path has capacity left and this one hasn't, the
    00194      * other one's better (thus, return true). */
    00195     return this->free_capacity > 0 ? (base->distance + dist < this->distance) : true;
    00196   } else {
    00197     /* If the other path doesn't have capacity left, but this one has,
    00198      * the other one is worse (thus, return false).
    00199      * If both paths are out of capacity, do the regular distance
    00200      * comparison. */
    00201     return this->free_capacity > 0 ? false : (base->distance + dist < this->distance);
    00202   }
    00203 }
    00204
    00214 bool CapacityAnnotation::IsBetter(const CapacityAnnotation *base, uint cap,
    00215     int free_cap, uint dist) const
    00216 {
    00217   int min_cap = Path::GetCapacityRatio(min(base->free_capacity, free_cap), min(base->capacity, cap));
    00218   int this_cap = this->GetCapacityRatio();
    00219   if (min_cap == this_cap) {
    00220     /* If the capacities are the same and the other path isn't disconnected
    00221      * choose the shorter path. */
    00222     return base->distance == UINT_MAX ? false : (base->distance + dist < this->distance);
    00223   } else {
    00224     return min_cap > this_cap;
    00225   }
    00226 }
    00227
    00237 template<class Tannotation, class Tedge_iterator>
    00238 void MultiCommodityFlow::Dijkstra(NodeID source_node, PathVector &paths)
    00239 {
    00240   typedef std::set<Tannotation *, typename Tannotation::Comparator> AnnoSet;
    00241   Tedge_iterator iter(this->job);
    00242   uint size = this->job.Size();
    00243   AnnoSet annos;
    00244   paths.resize(size, NULL);
    00245   for (NodeID node = 0; node < size; ++node) {
    00246     Tannotation *anno = new Tannotation(node, node == source_node);
    00247     annos.insert(anno);
    00248     paths[node] = anno;
    00249   }
    00250   while (!annos.empty()) {
    00251     typename AnnoSet::iterator i = annos.begin();
    00252     Tannotation *source = *i;
    00253     annos.erase(i);
    00254     NodeID from = source->GetNode();
    00255     iter.SetNode(source_node, from);
    00256     for (NodeID to = iter.Next(); to != INVALID_NODE; to = iter.Next()) {
    00257       if (to == from) continue; // Not a real edge but a consumption sign.
    00258       Edge edge = this->job[from][to];
    00259       assert(edge.Distance() < UINT_MAX);
    00260       uint capacity = edge.Capacity();
    00261       if (this->max_saturation != UINT_MAX) {
    00262         capacity *= this->max_saturation;
    00263         capacity /= 100;
    00264         if (capacity == 0) capacity = 1;
    00265       }
    00266       /* punish in-between stops a little */
    00267       uint distance = edge.Distance() + 1;
    00268       Tannotation *dest = static_cast<Tannotation *>(paths[to]);
    00269       if (dest->IsBetter(source, capacity, capacity - edge.Flow(), distance)) {
    00270         annos.erase(dest);
    00271         dest->Fork(source, capacity, capacity - edge.Flow(), distance);
    00272         annos.insert(dest);
    00273       }
    00274     }
    00275   }
    00276 }
    00277
    00283 void MultiCommodityFlow::CleanupPaths(NodeID source_id, PathVector &paths)
    00284 {
    00285   Path *source = paths[source_id];
    00286   paths[source_id] = NULL;
    00287   for (PathVector::iterator i = paths.begin(); i != paths.end(); ++i) {
    00288     Path *path = *i;
    00289     if (path == NULL) continue;
    00290     if (path->GetParent() == source) path->Detach();
    00291     while (path != source && path != NULL && path->GetFlow() == 0) {
    00292       Path *parent = path->GetParent();
    00293       path->Detach();
    00294       if (path->GetNumChildren() == 0) {
    00295         paths[path->GetNode()] = NULL;
    00296         delete path;
    00297       }
    00298       path = parent;
    00299     }
    00300   }
    00301   delete source;
    00302   paths.clear();
    00303 }
    00304
    00314 uint MultiCommodityFlow::PushFlow(Edge &edge, Path *path, uint accuracy,
    00315     uint max_saturation)
    00316 {
    00317   assert(edge.UnsatisfiedDemand() > 0);
    00318   uint flow = Clamp(edge.Demand() / accuracy, 1, edge.UnsatisfiedDemand());
    00319   flow = path->AddFlow(flow, this->job, max_saturation);
    00320   edge.SatisfyDemand(flow);
    00321   return flow;
    00322 }
    00323
    00330 uint MCF1stPass::FindCycleFlow(const PathVector &path, const Path *cycle_begin)
    00331 {
    00332   uint flow = UINT_MAX;
    00333   const Path *cycle_end = cycle_begin;
    00334   do {
    00335     flow = min(flow, cycle_begin->GetFlow());
    00336     cycle_begin = path[cycle_begin->GetNode()];
    00337   } while (cycle_begin != cycle_end);
    00338   return flow;
    00339 }
    00340
    00347 void MCF1stPass::EliminateCycle(PathVector &path, Path *cycle_begin, uint flow)
    00348 {
    00349   Path *cycle_end = cycle_begin;
    00350   do {
    00351     NodeID prev = cycle_begin->GetNode();
    00352     cycle_begin->ReduceFlow(flow);
    00353     cycle_begin = path[cycle_begin->GetNode()];
    00354     Edge edge = this->job[prev][cycle_begin->GetNode()];
    00355     edge.RemoveFlow(flow);
    00356   } while (cycle_begin != cycle_end);
    00357 }
    00358
    00368 bool MCF1stPass::EliminateCycles(PathVector &path, NodeID origin_id, NodeID next_id)
    00369 {
    00370   static Path *invalid_path = new Path(INVALID_NODE, true);
    00371   Path *at_next_pos = path[next_id];
    00372
    00373   /* this node has already been searched */
    00374   if (at_next_pos == invalid_path) return false;
    00375
    00376   if (at_next_pos == NULL) {
    00377     /* Summarize paths; add up the paths with the same source and next hop
    00378      * in one path each. */
    00379     PathSet &paths = this->job[next_id].Paths();
    00380     PathViaMap next_hops;
    00381     for (PathSet::iterator i = paths.begin(); i != paths.end(); ++i) {
    00382       Path *new_child = *i;
    00383       if (new_child->GetOrigin() == origin_id) {
    00384         PathViaMap::iterator via_it = next_hops.find(new_child->GetNode());
    00385         if (via_it == next_hops.end()) {
    00386           next_hops[new_child->GetNode()] = new_child;
    00387         } else {
    00388           Path *child = via_it->second;
    00389           uint new_flow = new_child->GetFlow();
    00390           child->AddFlow(new_flow);
    00391           new_child->ReduceFlow(new_flow);
    00392         }
    00393       }
    00394     }
    00395     bool found = false;
    00396     /* Search the next hops for nodes we have already visited */
    00397     for (PathViaMap::iterator via_it = next_hops.begin();
    00398         via_it != next_hops.end(); ++via_it) {
    00399       Path *child = via_it->second;
    00400       if (child->GetFlow() > 0) {
    00401         /* Push one child into the path vector and search this child's
    00402          * children. */
    00403         path[next_id] = child;
    00404         found = this->EliminateCycles(path, origin_id, child->GetNode()) || found;
    00405       }
    00406     }
    00407     /* All paths departing from this node have been searched. Mark as
    00408      * resolved if no cycles found. If cycles were found further cycles
    00409      * could be found in this branch, thus it has to be searched again next
    00410      * time we spot it.
    00411      */
    00412     path[next_id] = found ? NULL : invalid_path;
    00413     return found;
    00414   }
    00415
    00416   /* This node has already been visited => we have a cycle.
    00417    * Backtrack to find the exact flow. */
    00418   uint flow = this->FindCycleFlow(path, at_next_pos);
    00419   if (flow > 0) {
    00420     this->EliminateCycle(path, at_next_pos, flow);
    00421     return true;
    00422   }
    00423
    00424   return false;
    00425 }
    00426
    00432 bool MCF1stPass::EliminateCycles()
    00433 {
    00434   bool cycles_found = false;
    00435   uint size = this->job.Size();
    00436   PathVector path(size, NULL);
    00437   for (NodeID node = 0; node < size; ++node) {
    00438     /* Starting at each node in the graph find all cycles involving this
    00439      * node. */
    00440     std::fill(path.begin(), path.end(), (Path *)NULL);
    00441     cycles_found |= this->EliminateCycles(path, node, node);
    00442   }
    00443   return cycles_found;
    00444 }
    00445
    00450 MCF1stPass::MCF1stPass(LinkGraphJob &job) : MultiCommodityFlow(job)
    00451 {
    00452   PathVector paths;
    00453   uint size = job.Size();
    00454   uint accuracy = job.Settings().accuracy;
    00455   bool more_loops;
    00456
    00457   do {
    00458     more_loops = false;
    00459     for (NodeID source = 0; source < size; ++source) {
    00460       /* First saturate the shortest paths. */
    00461       this->Dijkstra<DistanceAnnotation, GraphEdgeIterator>(source, paths);
    00462
    00463       for (NodeID dest = 0; dest < size; ++dest) {
    00464         Edge edge = job[source][dest];
    00465         if (edge.UnsatisfiedDemand() > 0) {
    00466           Path *path = paths[dest];
    00467           assert(path != NULL);
    00468           /* Generally only allow paths that don't exceed the
    00469            * available capacity. But if no demand has been assigned
    00470            * yet, make an exception and allow any valid path *once*. */
    00471           if (path->GetFreeCapacity() > 0 && this->PushFlow(edge, path,
    00472               accuracy, this->max_saturation) > 0) {
    00473             /* If a path has been found there is a chance we can
    00474              * find more. */
    00475             more_loops = more_loops || (edge.UnsatisfiedDemand() > 0);
    00476           } else if (edge.UnsatisfiedDemand() == edge.Demand() &&
    00477               path->GetFreeCapacity() > INT_MIN) {
    00478             this->PushFlow(edge, path, accuracy, UINT_MAX);
    00479           }
    00480         }
    00481       }
    00482       this->CleanupPaths(source, paths);
    00483     }
    00484   } while (more_loops || this->EliminateCycles());
    00485 }
    00486
    00492 MCF2ndPass::MCF2ndPass(LinkGraphJob &job) : MultiCommodityFlow(job)
    00493 {
    00494   this->max_saturation = UINT_MAX; // disable artificial cap on saturation
    00495   PathVector paths;
    00496   uint size = job.Size();
    00497   uint accuracy = job.Settings().accuracy;
    00498   bool demand_left = true;
    00499   while (demand_left) {
    00500     demand_left = false;
    00501     for (NodeID source = 0; source < size; ++source) {
    00502       this->Dijkstra<CapacityAnnotation, FlowEdgeIterator>(source, paths);
    00503       for (NodeID dest = 0; dest < size; ++dest) {
    00504         Edge edge = this->job[source][dest];
    00505         Path *path = paths[dest];
    00506         if (edge.UnsatisfiedDemand() > 0 && path->GetFreeCapacity() > INT_MIN) {
    00507           this->PushFlow(edge, path, accuracy, UINT_MAX);
    00508           if (edge.UnsatisfiedDemand() > 0) demand_left = true;
    00509         }
    00510       }
    00511       this->CleanupPaths(source, paths);
    00512     }
    00513   }
    00514 }
    00515
    00527 template <typename T>
    00528 bool Greater(T x_anno, T y_anno, NodeID x, NodeID y)
    00529 {
    00530   if (x_anno > y_anno) return true;
    00531   if (x_anno < y_anno) return false;
    00532   return x > y;
    00533 }
    00534
    00541 bool CapacityAnnotation::Comparator::operator()(const CapacityAnnotation *x,
    00542     const CapacityAnnotation *y) const
    00543 {
    00544   return x != y && Greater<int>(x->GetAnnotation(), y->GetAnnotation(),
    00545       x->GetNode(), y->GetNode());
    00546 }
    00547
    00554 bool DistanceAnnotation::Comparator::operator()(const DistanceAnnotation *x,
    00555     const DistanceAnnotation *y) const
    00556 {
    00557   return x != y && !Greater<uint>(x->GetAnnotation(), y->GetAnnotation(),
    00558       x->GetNode(), y->GetNode());
    00559 }