# 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   if (base->distance == UINT_MAX) {
    00022     return false;
    00023   } else if (this->distance == UINT_MAX) {
    00024     return true;
    00025   }
    00026
    00027   if (free_cap > 0 && base->free_capacity > 0) {
    00028     /* If both paths have capacity left, compare their distances.
    00029      * If the other path has capacity left and this one hasn't, the
    00030      * other one's better (thus, return true). */
    00031     return this->free_capacity > 0 ? (base->distance + dist < this->distance) : true;
    00032   } else {
    00033     /* If the other path doesn't have capacity left, but this one has,
    00034      * the other one is worse (thus, return false).
    00035      * If both paths are out of capacity, do the regular distance
    00036      * comparison. */
    00037     return this->free_capacity > 0 ? false : (base->distance + dist < this->distance);
    00038   }
    00039 }
    00040
    00050 bool CapacityAnnotation::IsBetter(const CapacityAnnotation *base, uint cap,
    00051     int free_cap, uint dist) const
    00052 {
    00053   int min_cap = Path::GetCapacityRatio(min(base->free_capacity, free_cap), min(base->capacity, cap));
    00054   int this_cap = this->GetCapacityRatio();
    00055   if (min_cap == this_cap) {
    00056     /* If the capacities are the same and the other path isn't disconnected
    00057      * choose the shorter path. */
    00058     return base->distance == UINT_MAX ? false : (base->distance + dist < this->distance);
    00059   } else {
    00060     return min_cap > this_cap;
    00061   }
    00062 }
    00063
    00077 template<class Tannotation>
    00078 void MultiCommodityFlow::Dijkstra(NodeID source_node, PathVector &paths,
    00079     bool create_new_paths)
    00080 {
    00081   typedef std::set<Tannotation *, typename Tannotation::Comparator> AnnoSet;
    00082   uint size = this->graph->GetSize();
    00083   StationID source_station = this->graph->GetNode(source_node).station;
    00084   AnnoSet annos;
    00085   paths.resize(size, NULL);
    00086   for (NodeID node = 0; node < size; ++node) {
    00087     Tannotation *anno = new Tannotation(node, node == source_node);
    00088     annos.insert(anno);
    00089     paths[node] = anno;
    00090   }
    00091   while (!annos.empty()) {
    00092     typename AnnoSet::iterator i = annos.begin();
    00093     Tannotation *source = *i;
    00094     annos.erase(i);
    00095     NodeID from = source->GetNode();
    00096     NodeID to = this->graph->GetFirstEdge(from);
    00097     while (to != INVALID_NODE) {
    00098       Edge &edge = this->graph->GetEdge(from, to);
    00099       assert(edge.distance < UINT_MAX);
    00100       if (create_new_paths || this->graph->GetNode(from)
    00101           .flows[source_station][this->graph->GetNode(to).station] > 0) {
    00102         uint capacity = edge.capacity;
    00103         if (create_new_paths) {
    00104           capacity *= this->graph->GetSettings().short_path_saturation;
    00105           capacity /= 100;
    00106           if (capacity == 0) capacity = 1;
    00107         }
    00108         /* punish in-between stops a little */
    00109         uint distance = edge.distance + 1;
    00110         Tannotation *dest = static_cast<Tannotation *>(paths[to]);
    00111         if (dest->IsBetter(source, capacity, capacity - edge.flow, distance)) {
    00112           annos.erase(dest);
    00113           dest->Fork(source, capacity, capacity - edge.flow, distance);
    00114           annos.insert(dest);
    00115         }
    00116       }
    00117       to = edge.next_edge;
    00118     }
    00119   }
    00120 }
    00121
    00127 void MultiCommodityFlow::CleanupPaths(NodeID source_id, PathVector &paths)
    00128 {
    00129   Path *source = paths[source_id];
    00130   paths[source_id] = NULL;
    00131   for (PathVector::iterator i = paths.begin(); i != paths.end(); ++i) {
    00132     Path *path = *i;
    00133     if (path == NULL) continue;
    00134     if (path->GetParent() == source) path->Detach();
    00135     while (path != source && path != NULL && path->GetFlow() == 0) {
    00136       Path *parent = path->GetParent();
    00137       path->Detach();
    00138       if (path->GetNumChildren() == 0) {
    00139         paths[path->GetNode()] = NULL;
    00140         delete path;
    00141       }
    00142       path = parent;
    00143     }
    00144   }
    00145   delete source;
    00146   paths.clear();
    00147 }
    00148
    00158 uint MultiCommodityFlow::PushFlow(Edge &edge, Path *path, uint accuracy,
    00159     bool positive_cap)
    00160 {
    00161   assert(edge.unsatisfied_demand > 0);
    00162   uint flow = Clamp(edge.demand / accuracy, 1, edge.unsatisfied_demand);
    00163   flow = path->AddFlow(flow, this->graph, positive_cap);
    00164   edge.unsatisfied_demand -= flow;
    00165   return flow;
    00166 }
    00167
    00174 uint MCF1stPass::FindCycleFlow(const PathVector &path, const Path *cycle_begin)
    00175 {
    00176   uint flow = UINT_MAX;
    00177   const Path *cycle_end = cycle_begin;
    00178   do {
    00179     flow = min(flow, cycle_begin->GetFlow());
    00180     cycle_begin = path[cycle_begin->GetNode()];
    00181   } while (cycle_begin != cycle_end);
    00182   return flow;
    00183 }
    00184
    00191 void MCF1stPass::EliminateCycle(PathVector &path, Path *cycle_begin, uint flow)
    00192 {
    00193   Path *cycle_end = cycle_begin;
    00194   do {
    00195     NodeID prev = cycle_begin->GetNode();
    00196     cycle_begin->ReduceFlow(flow);
    00197     cycle_begin = path[cycle_begin->GetNode()];
    00198     Edge &edge = this->graph->GetEdge(prev, cycle_begin->GetNode());
    00199     edge.flow -= flow;
    00200   } while (cycle_begin != cycle_end);
    00201 }
    00202
    00212 bool MCF1stPass::EliminateCycles(PathVector &path, NodeID origin_id, NodeID next_id)
    00213 {
    00214   static Path *invalid_path = new Path(INVALID_NODE, true);
    00215   Path *at_next_pos = path[next_id];
    00216
    00217   /* this node has already been searched */
    00218   if (at_next_pos == invalid_path) return false;
    00219
    00220   if (at_next_pos == NULL) {
    00221     /* Summarize paths; add up the paths with the same source and next hop
    00222      * in one path each. */
    00223     PathSet &paths = this->graph->GetNode(next_id).paths;
    00224     PathViaMap next_hops;
    00225     for (PathSet::iterator i = paths.begin(); i != paths.end(); ++i) {
    00226       Path *new_child = *i;
    00227       if (new_child->GetOrigin() == origin_id) {
    00228         PathViaMap::iterator via_it = next_hops.find(new_child->GetNode());
    00229         if (via_it == next_hops.end()) {
    00230           next_hops[new_child->GetNode()] = new_child;
    00231         } else {
    00232           Path *child = via_it->second;
    00233           uint new_flow = new_child->GetFlow();
    00234           child->AddFlow(new_flow);
    00235           new_child->ReduceFlow(new_flow);
    00236         }
    00237       }
    00238     }
    00239     bool found = false;
    00240     /* Search the next hops for nodes we have already visited */
    00241     for (PathViaMap::iterator via_it = next_hops.begin();
    00242         via_it != next_hops.end(); ++via_it) {
    00243       Path *child = via_it->second;
    00244       if (child->GetFlow() > 0) {
    00245         /* Push one child into the path vector and search this child's
    00246          * children. */
    00247         path[next_id] = child;
    00248         found = this->EliminateCycles(path, origin_id, child->GetNode()) || found;
    00249       }
    00250     }
    00251     /* All paths departing from this node have been searched. Mark as
    00252      * resolved if no cycles found. If cycles were found further cycles
    00253      * could be found in this branch, thus it has to be searched again next
    00254      * time we spot it.
    00255      */
    00256     path[next_id] = found ? NULL : invalid_path;
    00257     return found;
    00258   }
    00259
    00260   /* This node has already been visited => we have a cycle.
    00261    * Backtrack to find the exact flow. */
    00262   uint flow = this->FindCycleFlow(path, at_next_pos);
    00263   if (flow > 0) {
    00264     this->EliminateCycle(path, at_next_pos, flow);
    00265     return true;
    00266   }
    00267
    00268   return false;
    00269 }
    00270
    00276 bool MCF1stPass::EliminateCycles()
    00277 {
    00278   bool cycles_found = false;
    00279   uint size = this->graph->GetSize();
    00280   PathVector path(size, NULL);
    00281   for (NodeID node = 0; node < size; ++node) {
    00282     /* Starting at each node in the graph find all cycles involving this
    00283      * node. */
    00284     std::fill(path.begin(), path.end(), (Path *)NULL);
    00285     cycles_found |= this->EliminateCycles(path, node, node);
    00286   }
    00287   return cycles_found;
    00288 }
    00289
    00294 MCF1stPass::MCF1stPass(LinkGraphComponent *graph) : MultiCommodityFlow(graph)
    00295 {
    00296   PathVector paths;
    00297   uint size = this->graph->GetSize();
    00298   uint accuracy = this->graph->GetSettings().accuracy;
    00299   bool more_loops = false;
    00300
    00301   do {
    00302     for (NodeID source = 0; source < size; ++source) {
    00303       /* First saturate the shortest paths. */
    00304       this->Dijkstra<DistanceAnnotation>(source, paths, true);
    00305
    00306       for (NodeID dest = 0; dest < size; ++dest) {
    00307         Edge &edge = this->graph->GetEdge(source, dest);
    00308         if (edge.unsatisfied_demand > 0) {
    00309           Path *path = paths[dest];
    00310           assert(path != NULL);
    00311           /* Generally only allow paths that don't exceed the
    00312            * available capacity. But if no demand has been assigned
    00313            * yet, make an exception and allow any valid path *once*. */
    00314           if (path->GetFreeCapacity() > 0 && this->PushFlow(edge, path,
    00315               accuracy, true) > 0) {
    00316             /* If a path has been found there is a chance we can
    00317              * find more. */
    00318             more_loops = (edge.unsatisfied_demand > 0);
    00319           } else if (edge.unsatisfied_demand == edge.demand &&
    00320               path->GetFreeCapacity() > INT_MIN) {
    00321             this->PushFlow(edge, path, accuracy, false);
    00322           }
    00323         }
    00324       }
    00325       this->CleanupPaths(source, paths);
    00326     }
    00327   } while (more_loops || this->EliminateCycles());
    00328 }
    00329
    00335 MCF2ndPass::MCF2ndPass(LinkGraphComponent *graph) : MultiCommodityFlow(graph)
    00336 {
    00337   PathVector paths;
    00338   uint size = this->graph->GetSize();
    00339   uint accuracy = this->graph->GetSettings().accuracy;
    00340   bool demand_left = true;
    00341   while (demand_left) {
    00342     demand_left = false;
    00343     for (NodeID source = 0; source < size; ++source) {
    00344       this->Dijkstra<CapacityAnnotation>(source, paths, false);
    00345       for (NodeID dest = 0; dest < size; ++dest) {
    00346         Edge &edge = this->graph->GetEdge(source, dest);
    00347         Path *path = paths[dest];
    00348         if (edge.unsatisfied_demand > 0 && path->GetFreeCapacity() > INT_MIN) {
    00349           this->PushFlow(edge, path, accuracy, false);
    00350           if (edge.unsatisfied_demand > 0) demand_left = true;
    00351         }
    00352       }
    00353       this->CleanupPaths(source, paths);
    00354     }
    00355   }
    00356 }
    00357
    00369 template <typename T>
    00370 bool Greater(T x_anno, T y_anno, NodeID x, NodeID y)
    00371 {
    00372   if (x_anno > y_anno) return true;
    00373   if (x_anno < y_anno) return false;
    00374   return x > y;
    00375 }
    00376
    00383 bool CapacityAnnotation::Comparator::operator()(const CapacityAnnotation *x,
    00384     const CapacityAnnotation *y) const
    00385 {
    00386   return x != y && Greater<int>(x->GetAnnotation(), y->GetAnnotation(),
    00387       x->GetNode(), y->GetNode());
    00388 }
    00389
    00396 bool DistanceAnnotation::Comparator::operator()(const DistanceAnnotation *x,
    00397     const DistanceAnnotation *y) const
    00398 {
    00399   return x != y && !Greater<uint>(x->GetAnnotation(), y->GetAnnotation(),
    00400       x->GetNode(), y->GetNode());
    00401 }