# 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
    00016 bool DistanceAnnotation::IsBetter(const DistanceAnnotation *base, uint cap,
    00017     int free_cap, uint dist) const
    00018 {
    00019   /* If any of the paths is disconnected, the other one is better. If both
    00020    * are disconnected, this path is better.
    00021    */
    00022   if (base->distance == UINT_MAX) {
    00023     return false;
    00024   } else if (this->distance == UINT_MAX) {
    00025     return true;
    00026   }
    00027
    00028   if (free_cap > 0 && base->free_capacity > 0) {
    00029     /* If both paths have capacity left, compare their distances.
    00030      * If the other path has capacity left and this one hasn't, the
    00031      * other one's better.
    00032      */
    00033     return this->free_capacity > 0 ? (base->distance + dist < this->distance) : true;
    00034   } else {
    00035     /* If the other path doesn't have capacity left, but this one has,
    00036      * this one is better.
    00037      * If both paths are out of capacity, do the regular distance
    00038      * comparison.
    00039      */
    00040     return this->free_capacity > 0 ? false : (base->distance + dist < this->distance);
    00041   }
    00042 }
    00043
    00053 bool CapacityAnnotation::IsBetter(const CapacityAnnotation *base, uint cap,
    00054     int free_cap, uint dist) const
    00055 {
    00056   int min_cap = (min(base->free_capacity, free_cap) << 4) / (min(base->capacity, cap) + 1);
    00057   int this_cap = this->GetCapacityRatio();
    00058   if (min_cap == this_cap) {
    00059     /* If the capacities are the same and the other path isn't disconnected
    00060      * choose the shorter path.
    00061      */
    00062     return base->distance == UINT_MAX ? false : (base->distance + dist < this->distance);
    00063   } else {
    00064     return min_cap > this_cap;
    00065   }
    00066 }
    00067
    00081 template<class Tannotation>
    00082 void MultiCommodityFlow::Dijkstra(NodeID source_node, PathVector &paths,
    00083     bool create_new_paths)
    00084 {
    00085   typedef std::set<Tannotation *, typename Tannotation::Comparator> AnnoSet;
    00086   uint size = this->graph->GetSize();
    00087   StationID source_station = this->graph->GetNode(source_node).station;
    00088   AnnoSet annos;
    00089   paths.resize(size, NULL);
    00090   for (NodeID node = 0; node < size; ++node) {
    00091     Tannotation *anno = new Tannotation(node, node == source_node);
    00092     annos.insert(anno);
    00093     paths[node] = anno;
    00094   }
    00095   while (!annos.empty()) {
    00096     typename AnnoSet::iterator i = annos.begin();
    00097     Tannotation *source = *i;
    00098     annos.erase(i);
    00099     NodeID from = source->GetNode();
    00100     NodeID to = this->graph->GetFirstEdge(from);
    00101     while (to != INVALID_NODE) {
    00102       Edge &edge = this->graph->GetEdge(from, to);
    00103       assert(edge.distance < UINT_MAX);
    00104       if (create_new_paths || this->graph->GetNode(from)
    00105           .flows[source_station][this->graph->GetNode(to).station] > 0) {
    00106         uint capacity = edge.capacity;
    00107         if (create_new_paths) {
    00108           capacity *= this->graph->GetSettings().short_path_saturation;
    00109           capacity /= 100;
    00110           if (capacity == 0) capacity = 1;
    00111         }
    00112         /* punish in-between stops a little */
    00113         uint distance = edge.distance + 1;
    00114         Tannotation *dest = static_cast<Tannotation *>(paths[to]);
    00115         if (dest->IsBetter(source, capacity, capacity - edge.flow, distance)) {
    00116           annos.erase(dest);
    00117           dest->Fork(source, capacity, capacity - edge.flow, distance);
    00118           annos.insert(dest);
    00119         }
    00120       }
    00121       to = edge.next_edge;
    00122     }
    00123   }
    00124 }
    00125
    00131 void MultiCommodityFlow::CleanupPaths(NodeID source_id, PathVector &paths)
    00132 {
    00133   Path *source = paths[source_id];
    00134   paths[source_id] = NULL;
    00135   for (PathVector::iterator i = paths.begin(); i != paths.end(); ++i) {
    00136     Path *path = *i;
    00137     if (path == NULL) continue;
    00138     if (path->GetParent() == source) path->Detach();
    00139     while (path != source && path != NULL && path->GetFlow() == 0) {
    00140       Path *parent = path->GetParent();
    00141       path->Detach();
    00142       if (path->GetNumChildren() == 0) {
    00143         paths[path->GetNode()] = NULL;
    00144         delete path;
    00145       }
    00146       path = parent;
    00147     }
    00148   }
    00149   delete source;
    00150   paths.clear();
    00151 }
    00152
    00162 uint MultiCommodityFlow::PushFlow(Edge &edge, Path *path, uint accuracy,
    00163     bool positive_cap)
    00164 {
    00165   assert(edge.unsatisfied_demand > 0);
    00166   uint flow = Clamp(edge.demand / accuracy, 1, edge.unsatisfied_demand);
    00167   flow = path->AddFlow(flow, this->graph, positive_cap);
    00168   edge.unsatisfied_demand -= flow;
    00169   return flow;
    00170 }
    00171
    00178 uint MCF1stPass::FindCycleFlow(const PathVector &path, const Path *cycle_begin)
    00179 {
    00180   uint flow = UINT_MAX;
    00181   const Path *cycle_end = cycle_begin;
    00182   do {
    00183     flow = min(flow, cycle_begin->GetFlow());
    00184     cycle_begin = path[cycle_begin->GetNode()];
    00185   } while (cycle_begin != cycle_end);
    00186   return flow;
    00187 }
    00188
    00195 void MCF1stPass::EliminateCycle(PathVector &path, Path *cycle_begin, uint flow)
    00196 {
    00197   Path *cycle_end = cycle_begin;
    00198   do {
    00199     NodeID prev = cycle_begin->GetNode();
    00200     cycle_begin->ReduceFlow(flow);
    00201     cycle_begin = path[cycle_begin->GetNode()];
    00202     Edge &edge = this->graph->GetEdge(prev, cycle_begin->GetNode());
    00203     edge.flow -= flow;
    00204   } while (cycle_begin != cycle_end);
    00205 }
    00206
    00216 bool MCF1stPass::EliminateCycles(PathVector &path, NodeID origin_id, NodeID next_id)
    00217 {
    00218   static Path *invalid_path = new Path(INVALID_NODE, true);
    00219   Path *at_next_pos = path[next_id];
    00220   if (at_next_pos == invalid_path) {
    00221     /* this node has already been searched */
    00222     return false;
    00223   } else if (at_next_pos == NULL) {
    00224     /* summarize paths; add up the paths with the same source and next hop
    00225      * in one path each
    00226      */
    00227     PathSet &paths = this->graph->GetNode(next_id).paths;
    00228     PathViaMap next_hops;
    00229     for (PathSet::iterator i = paths.begin(); i != paths.end(); ++i) {
    00230       Path *new_child = *i;
    00231       if (new_child->GetOrigin() == origin_id) {
    00232         PathViaMap::iterator via_it = next_hops.find(new_child->GetNode());
    00233         if (via_it == next_hops.end()) {
    00234           next_hops[new_child->GetNode()] = new_child;
    00235         } else {
    00236           Path *child = via_it->second;
    00237           uint new_flow = new_child->GetFlow();
    00238           child->AddFlow(new_flow);
    00239           new_child->ReduceFlow(new_flow);
    00240         }
    00241       }
    00242     }
    00243     bool found = false;
    00244     /* search the next hops for nodes we have already visited */
    00245     for (PathViaMap::iterator via_it = next_hops.begin();
    00246         via_it != next_hops.end(); ++via_it) {
    00247       Path *child = via_it->second;
    00248       if (child->GetFlow() > 0) {
    00249         /* push one child into the path vector and search this child's
    00250          * children
    00251          */
    00252         path[next_id] = child;
    00253         found = this->EliminateCycles(path, origin_id, child->GetNode()) || found;
    00254       }
    00255     }
    00256     /* All paths departing from this node have been searched. Mark as
    00257      * resolved if no cycles found. If cycles were found further cycles
    00258      * could be found in this branch, thus it has to be searched again next
    00259      * time we spot it.
    00260      */
    00261     path[next_id] = found ? NULL : invalid_path;
    00262     return found;
    00263   } else {
    00264     /* this node has already been visited => we have a cycle
    00265      * backtrack to find the exact flow
    00266      */
    00267     uint flow = this->FindCycleFlow(path, at_next_pos);
    00268     if (flow > 0) {
    00269       this->EliminateCycle(path, at_next_pos, flow);
    00270       return true;
    00271     } else {
    00272       return false;
    00273     }
    00274   }
    00275 }
    00276
    00282 bool MCF1stPass::EliminateCycles()
    00283 {
    00284   bool cycles_found = false;
    00285   uint size = this->graph->GetSize();
    00286   PathVector path(size, NULL);
    00287   for (NodeID node = 0; node < size; ++node) {
    00288     /* starting at each node in the graph find all cycles involving this
    00289      * node
    00290      */
    00291     std::fill(path.begin(), path.end(), (Path *)NULL);
    00292     cycles_found |= this->EliminateCycles(path, node, node);
    00293   }
    00294   return cycles_found;
    00295 }
    00296
    00301 MCF1stPass::MCF1stPass(LinkGraphComponent *graph) : MultiCommodityFlow(graph)
    00302 {
    00303   PathVector paths;
    00304   uint size = this->graph->GetSize();
    00305   uint accuracy = this->graph->GetSettings().accuracy;
    00306   bool more_loops = true;
    00307
    00308   while (more_loops) {
    00309     more_loops = false;
    00310
    00311     for (NodeID source = 0; source < size; ++source) {
    00312       /* first saturate the shortest paths */
    00313       this->Dijkstra<DistanceAnnotation>(source, paths, true);
    00314
    00315       for (NodeID dest = 0; dest < size; ++dest) {
    00316         Edge &edge = this->graph->GetEdge(source, dest);
    00317         if (edge.unsatisfied_demand > 0) {
    00318           Path *path = paths[dest];
    00319           assert(path != NULL);
    00320           /* generally only allow paths that don't exceed the
    00321            * available capacity. But if no demand has been assigned
    00322            * yet, make an exception and allow any valid path *once*.
    00323            */
    00324           if (path->GetFreeCapacity() > 0 && this->PushFlow(edge, path,
    00325               accuracy, true) > 0) {
    00326             /* if a path has been found there is a chance we can
    00327              * find more
    00328              */
    00329             more_loops = (edge.unsatisfied_demand > 0);
    00330           } else if (edge.unsatisfied_demand == edge.demand &&
    00331               path->GetFreeCapacity() > INT_MIN) {
    00332             this->PushFlow(edge, path, accuracy, false);
    00333           }
    00334         }
    00335       }
    00336       this->CleanupPaths(source, paths);
    00337     }
    00338     if (!more_loops) more_loops = this->EliminateCycles();
    00339   }
    00340 }
    00341
    00347 MCF2ndPass::MCF2ndPass(LinkGraphComponent *graph) : MultiCommodityFlow(graph)
    00348 {
    00349   PathVector paths;
    00350   uint size = this->graph->GetSize();
    00351   uint accuracy = this->graph->GetSettings().accuracy;
    00352   bool demand_left = true;
    00353   while (demand_left) {
    00354     demand_left = false;
    00355     for (NodeID source = 0; source < size; ++source) {
    00356       this->Dijkstra<CapacityAnnotation>(source, paths, false);
    00357       for (NodeID dest = 0; dest < size; ++dest) {
    00358         Edge &edge = this->graph->GetEdge(source, dest);
    00359         Path *path = paths[dest];
    00360         if (edge.unsatisfied_demand > 0 && path->GetFreeCapacity() > INT_MIN) {
    00361           this->PushFlow(edge, path, accuracy, false);
    00362           if (edge.unsatisfied_demand > 0) demand_left = true;
    00363         }
    00364       }
    00365       this->CleanupPaths(source, paths);
    00366     }
    00367   }
    00368 }
    00369
    00381 template <typename T>
    00382 bool greater(T x_anno, T y_anno, NodeID x, NodeID y)
    00383 {
    00384   if (x_anno > y_anno) {
    00385     return true;
    00386   } else if (x_anno < y_anno) {
    00387     return false;
    00388   } else {
    00389     return x > y;
    00390   }
    00391 }
    00392
    00399 bool CapacityAnnotation::Comparator::operator()(const CapacityAnnotation *x,
    00400     const CapacityAnnotation *y) const
    00401 {
    00402   return x != y && greater<int>(x->GetAnnotation(), y->GetAnnotation(),
    00403       x->GetNode(), y->GetNode());
    00404 }
    00405
    00412 bool DistanceAnnotation::Comparator::operator()(const DistanceAnnotation *x,
    00413     const DistanceAnnotation *y) const
    00414 {
    00415   return x != y && !greater<uint>(x->GetAnnotation(), y->GetAnnotation(),
    00416       x->GetNode(), y->GetNode());
    00417 }