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 
00011 class GraphEdgeIterator {
00012 private:
00013   LinkGraph *graph; 
00014   NodeID from;      
00015   NodeID to;        
00016 
00017 public:
00018 
00023   GraphEdgeIterator(LinkGraphJob *job) : graph(&job->Graph()),
00024       from(INVALID_NODE), to(INVALID_NODE)
00025   {}
00026 
00032   void SetNode(NodeID source, NodeID node)
00033   {
00034     this->to = node;
00035     this->from = node;
00036   }
00037 
00042   NodeID Next()
00043   {
00044     if (this->to != INVALID_NODE) {
00045       this->to = this->graph->GetEdge(this->from, this->to).next_edge;
00046     }
00047     return this->to;
00048   }
00049 };
00050 
00054 class FlowEdgeIterator {
00055 private:
00056   LinkGraphJob *job; 
00057 
00059   std::map<StationID, NodeID> station_to_node;
00060 
00062   FlowStat::SharesMap::const_iterator it;
00063 
00065   FlowStat::SharesMap::const_iterator end;
00066 public:
00067 
00072   FlowEdgeIterator(LinkGraphJob *job) : job(job)
00073   {
00074     for (NodeID i = 0; i < job->Graph().GetSize(); ++i) {
00075       this->station_to_node[job->Graph().GetNode(i).station] = i;
00076     }
00077   }
00078 
00084   void SetNode(NodeID source, NodeID node)
00085   {
00086     static const FlowStat::SharesMap empty;
00087     FlowStatMap &flows = this->job->GetNode(node).flows;
00088     FlowStatMap::const_iterator it = flows.find(this->job->Graph().GetNode(source).station);
00089     if (it != flows.end()) {
00090       this->it = it->second.GetShares()->begin();
00091       this->end = it->second.GetShares()->end();
00092     } else {
00093       this->it = empty.begin();
00094       this->end = empty.end();
00095     }
00096   }
00097 
00102   NodeID Next()
00103   {
00104     if (this->it == this->end) return INVALID_NODE;
00105     return this->station_to_node[(this->it++)->second];
00106   }
00107 };
00108 
00118 bool DistanceAnnotation::IsBetter(const DistanceAnnotation *base, uint cap,
00119     int free_cap, uint dist) const
00120 {
00121   /* If any of the paths is disconnected, the other one is better. If both
00122    * are disconnected, this path is better.*/
00123   if (base->distance == UINT_MAX) {
00124     return false;
00125   } else if (this->distance == UINT_MAX) {
00126     return true;
00127   }
00128 
00129   if (free_cap > 0 && base->free_capacity > 0) {
00130     /* If both paths have capacity left, compare their distances.
00131      * If the other path has capacity left and this one hasn't, the
00132      * other one's better (thus, return true). */
00133     return this->free_capacity > 0 ? (base->distance + dist < this->distance) : true;
00134   } else {
00135     /* If the other path doesn't have capacity left, but this one has,
00136      * the other one is worse (thus, return false).
00137      * If both paths are out of capacity, do the regular distance
00138      * comparison. */
00139     return this->free_capacity > 0 ? false : (base->distance + dist < this->distance);
00140   }
00141 }
00142 
00152 bool CapacityAnnotation::IsBetter(const CapacityAnnotation *base, uint cap,
00153     int free_cap, uint dist) const
00154 {
00155   int min_cap = Path::GetCapacityRatio(min(base->free_capacity, free_cap), min(base->capacity, cap));
00156   int this_cap = this->GetCapacityRatio();
00157   if (min_cap == this_cap) {
00158     /* If the capacities are the same and the other path isn't disconnected
00159      * choose the shorter path. */
00160     return base->distance == UINT_MAX ? false : (base->distance + dist < this->distance);
00161   } else {
00162     return min_cap > this_cap;
00163   }
00164 }
00165 
00175 template<class Tannotation, class Tedge_iterator>
00176 void MultiCommodityFlow::Dijkstra(NodeID source_node, PathVector &paths)
00177 {
00178   typedef std::set<Tannotation *, typename Tannotation::Comparator> AnnoSet;
00179   Tedge_iterator iter(this->job);
00180   uint size = this->graph->GetSize();
00181   AnnoSet annos;
00182   paths.resize(size, NULL);
00183   for (NodeID node = 0; node < size; ++node) {
00184     Tannotation *anno = new Tannotation(node, node == source_node);
00185     annos.insert(anno);
00186     paths[node] = anno;
00187   }
00188   while (!annos.empty()) {
00189     typename AnnoSet::iterator i = annos.begin();
00190     Tannotation *source = *i;
00191     annos.erase(i);
00192     NodeID from = source->GetNode();
00193     iter.SetNode(source_node, from);
00194     for (NodeID to = iter.Next(); to != INVALID_NODE; to = iter.Next()) {
00195       if (to == from) continue; // Not a real edge but a consumption sign.
00196       Edge &edge = this->graph->GetEdge(from, to);
00197       assert(edge.distance < UINT_MAX);
00198       uint capacity = edge.capacity;
00199       if (this->max_saturation != UINT_MAX) {
00200         capacity *= this->max_saturation;
00201         capacity /= 100;
00202         if (capacity == 0) capacity = 1;
00203       }
00204       /* punish in-between stops a little */
00205       uint distance = edge.distance + 1;
00206       Tannotation *dest = static_cast<Tannotation *>(paths[to]);
00207       EdgeAnnotation &edge_anno = this->job->GetEdge(from, to);
00208       if (dest->IsBetter(source, capacity, capacity - edge_anno.flow, distance)) {
00209         annos.erase(dest);
00210         dest->Fork(source, capacity, capacity - edge_anno.flow, distance);
00211         annos.insert(dest);
00212       }
00213     }
00214   }
00215 }
00216 
00222 void MultiCommodityFlow::CleanupPaths(NodeID source_id, PathVector &paths)
00223 {
00224   Path *source = paths[source_id];
00225   paths[source_id] = NULL;
00226   for (PathVector::iterator i = paths.begin(); i != paths.end(); ++i) {
00227     Path *path = *i;
00228     if (path == NULL) continue;
00229     if (path->GetParent() == source) path->Detach();
00230     while (path != source && path != NULL && path->GetFlow() == 0) {
00231       Path *parent = path->GetParent();
00232       path->Detach();
00233       if (path->GetNumChildren() == 0) {
00234         paths[path->GetNode()] = NULL;
00235         delete path;
00236       }
00237       path = parent;
00238     }
00239   }
00240   delete source;
00241   paths.clear();
00242 }
00243 
00253 uint MultiCommodityFlow::PushFlow(EdgeAnnotation &edge, Path *path, uint accuracy,
00254     uint max_saturation)
00255 {
00256   assert(edge.unsatisfied_demand > 0);
00257   uint flow = Clamp(edge.demand / accuracy, 1, edge.unsatisfied_demand);
00258   flow = path->AddFlow(flow, this->job, max_saturation);
00259   edge.unsatisfied_demand -= flow;
00260   return flow;
00261 }
00262 
00269 uint MCF1stPass::FindCycleFlow(const PathVector &path, const Path *cycle_begin)
00270 {
00271   uint flow = UINT_MAX;
00272   const Path *cycle_end = cycle_begin;
00273   do {
00274     flow = min(flow, cycle_begin->GetFlow());
00275     cycle_begin = path[cycle_begin->GetNode()];
00276   } while (cycle_begin != cycle_end);
00277   return flow;
00278 }
00279 
00286 void MCF1stPass::EliminateCycle(PathVector &path, Path *cycle_begin, uint flow)
00287 {
00288   Path *cycle_end = cycle_begin;
00289   do {
00290     NodeID prev = cycle_begin->GetNode();
00291     cycle_begin->ReduceFlow(flow);
00292     cycle_begin = path[cycle_begin->GetNode()];
00293     EdgeAnnotation &edge = this->job->GetEdge(prev, cycle_begin->GetNode());
00294     edge.flow -= flow;
00295   } while (cycle_begin != cycle_end);
00296 }
00297 
00307 bool MCF1stPass::EliminateCycles(PathVector &path, NodeID origin_id, NodeID next_id)
00308 {
00309   static Path *invalid_path = new Path(INVALID_NODE, true);
00310   Path *at_next_pos = path[next_id];
00311 
00312   /* this node has already been searched */
00313   if (at_next_pos == invalid_path) return false;
00314 
00315   if (at_next_pos == NULL) {
00316     /* Summarize paths; add up the paths with the same source and next hop
00317      * in one path each. */
00318     PathSet &paths = this->job->GetNode(next_id).paths;
00319     PathViaMap next_hops;
00320     for (PathSet::iterator i = paths.begin(); i != paths.end(); ++i) {
00321       Path *new_child = *i;
00322       if (new_child->GetOrigin() == origin_id) {
00323         PathViaMap::iterator via_it = next_hops.find(new_child->GetNode());
00324         if (via_it == next_hops.end()) {
00325           next_hops[new_child->GetNode()] = new_child;
00326         } else {
00327           Path *child = via_it->second;
00328           uint new_flow = new_child->GetFlow();
00329           child->AddFlow(new_flow);
00330           new_child->ReduceFlow(new_flow);
00331         }
00332       }
00333     }
00334     bool found = false;
00335     /* Search the next hops for nodes we have already visited */
00336     for (PathViaMap::iterator via_it = next_hops.begin();
00337         via_it != next_hops.end(); ++via_it) {
00338       Path *child = via_it->second;
00339       if (child->GetFlow() > 0) {
00340         /* Push one child into the path vector and search this child's
00341          * children. */
00342         path[next_id] = child;
00343         found = this->EliminateCycles(path, origin_id, child->GetNode()) || found;
00344       }
00345     }
00346     /* All paths departing from this node have been searched. Mark as
00347      * resolved if no cycles found. If cycles were found further cycles
00348      * could be found in this branch, thus it has to be searched again next
00349      * time we spot it.
00350      */
00351     path[next_id] = found ? NULL : invalid_path;
00352     return found;
00353   }
00354 
00355   /* This node has already been visited => we have a cycle.
00356    * Backtrack to find the exact flow. */
00357   uint flow = this->FindCycleFlow(path, at_next_pos);
00358   if (flow > 0) {
00359     this->EliminateCycle(path, at_next_pos, flow);
00360     return true;
00361   }
00362 
00363   return false;
00364 }
00365 
00371 bool MCF1stPass::EliminateCycles()
00372 {
00373   bool cycles_found = false;
00374   uint size = this->graph->GetSize();
00375   PathVector path(size, NULL);
00376   for (NodeID node = 0; node < size; ++node) {
00377     /* Starting at each node in the graph find all cycles involving this
00378      * node. */
00379     std::fill(path.begin(), path.end(), (Path *)NULL);
00380     cycles_found |= this->EliminateCycles(path, node, node);
00381   }
00382   return cycles_found;
00383 }
00384 
00389 MCF1stPass::MCF1stPass(LinkGraphJob *job) : MultiCommodityFlow(job)
00390 {
00391   PathVector paths;
00392   uint size = this->graph->GetSize();
00393   uint accuracy = job->Settings().accuracy;
00394   bool more_loops;
00395 
00396   do {
00397     more_loops = false;
00398     for (NodeID source = 0; source < size; ++source) {
00399       /* First saturate the shortest paths. */
00400       this->Dijkstra<DistanceAnnotation, GraphEdgeIterator>(source, paths);
00401 
00402       for (NodeID dest = 0; dest < size; ++dest) {
00403         EdgeAnnotation &edge = this->job->GetEdge(source, dest);
00404         if (edge.unsatisfied_demand > 0) {
00405           Path *path = paths[dest];
00406           assert(path != NULL);
00407           /* Generally only allow paths that don't exceed the
00408            * available capacity. But if no demand has been assigned
00409            * yet, make an exception and allow any valid path *once*. */
00410           if (path->GetFreeCapacity() > 0 && this->PushFlow(edge, path,
00411               accuracy, this->max_saturation) > 0) {
00412             /* If a path has been found there is a chance we can
00413              * find more. */
00414             more_loops = more_loops || (edge.unsatisfied_demand > 0);
00415           } else if (edge.unsatisfied_demand == edge.demand &&
00416               path->GetFreeCapacity() > INT_MIN) {
00417             this->PushFlow(edge, path, accuracy, UINT_MAX);
00418           }
00419         }
00420       }
00421       this->CleanupPaths(source, paths);
00422     }
00423   } while (more_loops || this->EliminateCycles());
00424 }
00425 
00431 MCF2ndPass::MCF2ndPass(LinkGraphJob *job) : MultiCommodityFlow(job)
00432 {
00433   this->max_saturation = UINT_MAX; // disable artificial cap on saturation
00434   PathVector paths;
00435   uint size = this->graph->GetSize();
00436   uint accuracy = job->Settings().accuracy;
00437   bool demand_left = true;
00438   while (demand_left) {
00439     demand_left = false;
00440     for (NodeID source = 0; source < size; ++source) {
00441       this->Dijkstra<CapacityAnnotation, FlowEdgeIterator>(source, paths);
00442       for (NodeID dest = 0; dest < size; ++dest) {
00443         EdgeAnnotation &edge = this->job->GetEdge(source, dest);
00444         Path *path = paths[dest];
00445         if (edge.unsatisfied_demand > 0 && path->GetFreeCapacity() > INT_MIN) {
00446           this->PushFlow(edge, path, accuracy, UINT_MAX);
00447           if (edge.unsatisfied_demand > 0) demand_left = true;
00448         }
00449       }
00450       this->CleanupPaths(source, paths);
00451     }
00452   }
00453 }
00454 
00466 template <typename T>
00467 bool Greater(T x_anno, T y_anno, NodeID x, NodeID y)
00468 {
00469   if (x_anno > y_anno) return true;
00470   if (x_anno < y_anno) return false;
00471   return x > y;
00472 }
00473 
00480 bool CapacityAnnotation::Comparator::operator()(const CapacityAnnotation *x,
00481     const CapacityAnnotation *y) const
00482 {
00483   return x != y && Greater<int>(x->GetAnnotation(), y->GetAnnotation(),
00484       x->GetNode(), y->GetNode());
00485 }
00486 
00493 bool DistanceAnnotation::Comparator::operator()(const DistanceAnnotation *x,
00494     const DistanceAnnotation *y) const
00495 {
00496   return x != y && !Greater<uint>(x->GetAnnotation(), y->GetAnnotation(),
00497       x->GetNode(), y->GetNode());
00498 }