OpenTTD
mcf.cpp
Go to the documentation of this file.
1 
3 #include "../stdafx.h"
4 #include "../core/math_func.hpp"
5 #include "mcf.h"
6 #include <set>
7 
8 #include "../safeguards.h"
9 
10 typedef std::map<NodeID, Path *> PathViaMap;
11 
17 class DistanceAnnotation : public Path {
18 public:
19 
25  DistanceAnnotation(NodeID n, bool source = false) : Path(n, source) {}
26 
27  bool IsBetter(const DistanceAnnotation *base, uint cap, int free_cap, uint dist) const;
28 
33  inline uint GetAnnotation() const { return this->distance; }
34 
38  struct Comparator {
39  bool operator()(const DistanceAnnotation *x, const DistanceAnnotation *y) const;
40  };
41 };
42 
49 class CapacityAnnotation : public Path {
50 public:
51 
57  CapacityAnnotation(NodeID n, bool source = false) : Path(n, source) {}
58 
59  bool IsBetter(const CapacityAnnotation *base, uint cap, int free_cap, uint dist) const;
60 
65  inline int GetAnnotation() const { return this->GetCapacityRatio(); }
66 
70  struct Comparator {
71  bool operator()(const CapacityAnnotation *x, const CapacityAnnotation *y) const;
72  };
73 };
74 
80 private:
84 
85 public:
86 
92  i(NULL, NULL, INVALID_NODE), end(NULL, NULL, INVALID_NODE)
93  {}
94 
100  void SetNode(NodeID source, NodeID node)
101  {
102  this->i = this->job[node].Begin();
103  this->end = this->job[node].End();
104  }
105 
110  NodeID Next()
111  {
112  return this->i != this->end ? (this->i++)->first : INVALID_NODE;
113  }
114 };
115 
120 private:
122 
124  std::map<StationID, NodeID> station_to_node;
125 
127  FlowStat::SharesMap::const_iterator it;
128 
130  FlowStat::SharesMap::const_iterator end;
131 public:
132 
138  {
139  for (NodeID i = 0; i < job.Size(); ++i) {
140  this->station_to_node[job[i].Station()] = i;
141  }
142  }
143 
149  void SetNode(NodeID source, NodeID node)
150  {
151  static const FlowStat::SharesMap empty;
152  const FlowStatMap &flows = this->job[node].Flows();
153  FlowStatMap::const_iterator it = flows.find(this->job[source].Station());
154  if (it != flows.end()) {
155  this->it = it->second.GetShares()->begin();
156  this->end = it->second.GetShares()->end();
157  } else {
158  this->it = empty.begin();
159  this->end = empty.end();
160  }
161  }
162 
167  NodeID Next()
168  {
169  if (this->it == this->end) return INVALID_NODE;
170  return this->station_to_node[(this->it++)->second];
171  }
172 };
173 
184  int free_cap, uint dist) const
185 {
186  /* If any of the paths is disconnected, the other one is better. If both
187  * are disconnected, this path is better.*/
188  if (base->distance == UINT_MAX) {
189  return false;
190  } else if (this->distance == UINT_MAX) {
191  return true;
192  }
193 
194  if (free_cap > 0 && base->free_capacity > 0) {
195  /* If both paths have capacity left, compare their distances.
196  * If the other path has capacity left and this one hasn't, the
197  * other one's better (thus, return true). */
198  return this->free_capacity > 0 ? (base->distance + dist < this->distance) : true;
199  } else {
200  /* If the other path doesn't have capacity left, but this one has,
201  * the other one is worse (thus, return false).
202  * If both paths are out of capacity, do the regular distance
203  * comparison. */
204  return this->free_capacity > 0 ? false : (base->distance + dist < this->distance);
205  }
206 }
207 
218  int free_cap, uint dist) const
219 {
220  int min_cap = Path::GetCapacityRatio(min(base->free_capacity, free_cap), min(base->capacity, cap));
221  int this_cap = this->GetCapacityRatio();
222  if (min_cap == this_cap) {
223  /* If the capacities are the same and the other path isn't disconnected
224  * choose the shorter path. */
225  return base->distance == UINT_MAX ? false : (base->distance + dist < this->distance);
226  } else {
227  return min_cap > this_cap;
228  }
229 }
230 
240 template<class Tannotation, class Tedge_iterator>
241 void MultiCommodityFlow::Dijkstra(NodeID source_node, PathVector &paths)
242 {
243  typedef std::set<Tannotation *, typename Tannotation::Comparator> AnnoSet;
244  Tedge_iterator iter(this->job);
245  uint size = this->job.Size();
246  AnnoSet annos;
247  paths.resize(size, NULL);
248  for (NodeID node = 0; node < size; ++node) {
249  Tannotation *anno = new Tannotation(node, node == source_node);
250  annos.insert(anno);
251  paths[node] = anno;
252  }
253  while (!annos.empty()) {
254  typename AnnoSet::iterator i = annos.begin();
255  Tannotation *source = *i;
256  annos.erase(i);
257  NodeID from = source->GetNode();
258  iter.SetNode(source_node, from);
259  for (NodeID to = iter.Next(); to != INVALID_NODE; to = iter.Next()) {
260  if (to == from) continue; // Not a real edge but a consumption sign.
261  Edge edge = this->job[from][to];
262  uint capacity = edge.Capacity();
263  if (this->max_saturation != UINT_MAX) {
264  capacity *= this->max_saturation;
265  capacity /= 100;
266  if (capacity == 0) capacity = 1;
267  }
268  /* punish in-between stops a little */
269  uint distance = DistanceMaxPlusManhattan(this->job[from].XY(), this->job[to].XY()) + 1;
270  Tannotation *dest = static_cast<Tannotation *>(paths[to]);
271  if (dest->IsBetter(source, capacity, capacity - edge.Flow(), distance)) {
272  annos.erase(dest);
273  dest->Fork(source, capacity, capacity - edge.Flow(), distance);
274  annos.insert(dest);
275  }
276  }
277  }
278 }
279 
285 void MultiCommodityFlow::CleanupPaths(NodeID source_id, PathVector &paths)
286 {
287  Path *source = paths[source_id];
288  paths[source_id] = NULL;
289  for (PathVector::iterator i = paths.begin(); i != paths.end(); ++i) {
290  Path *path = *i;
291  if (path == NULL) continue;
292  if (path->GetParent() == source) path->Detach();
293  while (path != source && path != NULL && path->GetFlow() == 0) {
294  Path *parent = path->GetParent();
295  path->Detach();
296  if (path->GetNumChildren() == 0) {
297  paths[path->GetNode()] = NULL;
298  delete path;
299  }
300  path = parent;
301  }
302  }
303  delete source;
304  paths.clear();
305 }
306 
316 uint MultiCommodityFlow::PushFlow(Edge &edge, Path *path, uint accuracy,
317  uint max_saturation)
318 {
319  assert(edge.UnsatisfiedDemand() > 0);
320  uint flow = Clamp(edge.Demand() / accuracy, 1, edge.UnsatisfiedDemand());
321  flow = path->AddFlow(flow, this->job, max_saturation);
322  edge.SatisfyDemand(flow);
323  return flow;
324 }
325 
332 uint MCF1stPass::FindCycleFlow(const PathVector &path, const Path *cycle_begin)
333 {
334  uint flow = UINT_MAX;
335  const Path *cycle_end = cycle_begin;
336  do {
337  flow = min(flow, cycle_begin->GetFlow());
338  cycle_begin = path[cycle_begin->GetNode()];
339  } while (cycle_begin != cycle_end);
340  return flow;
341 }
342 
349 void MCF1stPass::EliminateCycle(PathVector &path, Path *cycle_begin, uint flow)
350 {
351  Path *cycle_end = cycle_begin;
352  do {
353  NodeID prev = cycle_begin->GetNode();
354  cycle_begin->ReduceFlow(flow);
355  if (cycle_begin->GetFlow() == 0) {
356  PathList &node_paths = this->job[cycle_begin->GetParent()->GetNode()].Paths();
357  for (PathList::iterator i = node_paths.begin(); i != node_paths.end(); ++i) {
358  if (*i == cycle_begin) {
359  node_paths.erase(i);
360  node_paths.push_back(cycle_begin);
361  break;
362  }
363  }
364  }
365  cycle_begin = path[prev];
366  Edge edge = this->job[prev][cycle_begin->GetNode()];
367  edge.RemoveFlow(flow);
368  } while (cycle_begin != cycle_end);
369 }
370 
380 bool MCF1stPass::EliminateCycles(PathVector &path, NodeID origin_id, NodeID next_id)
381 {
382  static Path *invalid_path = new Path(INVALID_NODE, true);
383  Path *at_next_pos = path[next_id];
384 
385  /* this node has already been searched */
386  if (at_next_pos == invalid_path) return false;
387 
388  if (at_next_pos == NULL) {
389  /* Summarize paths; add up the paths with the same source and next hop
390  * in one path each. */
391  PathList &paths = this->job[next_id].Paths();
392  PathViaMap next_hops;
393  for (PathList::iterator i = paths.begin(); i != paths.end();) {
394  Path *new_child = *i;
395  uint new_flow = new_child->GetFlow();
396  if (new_flow == 0) break;
397  if (new_child->GetOrigin() == origin_id) {
398  PathViaMap::iterator via_it = next_hops.find(new_child->GetNode());
399  if (via_it == next_hops.end()) {
400  next_hops[new_child->GetNode()] = new_child;
401  ++i;
402  } else {
403  Path *child = via_it->second;
404  child->AddFlow(new_flow);
405  new_child->ReduceFlow(new_flow);
406 
407  /* We might hit end() with with the ++ here and skip the
408  * newly push_back'ed path. That's good as the flow of that
409  * path is 0 anyway. */
410  paths.erase(i++);
411  paths.push_back(new_child);
412  }
413  } else {
414  ++i;
415  }
416  }
417  bool found = false;
418  /* Search the next hops for nodes we have already visited */
419  for (PathViaMap::iterator via_it = next_hops.begin();
420  via_it != next_hops.end(); ++via_it) {
421  Path *child = via_it->second;
422  if (child->GetFlow() > 0) {
423  /* Push one child into the path vector and search this child's
424  * children. */
425  path[next_id] = child;
426  found = this->EliminateCycles(path, origin_id, child->GetNode()) || found;
427  }
428  }
429  /* All paths departing from this node have been searched. Mark as
430  * resolved if no cycles found. If cycles were found further cycles
431  * could be found in this branch, thus it has to be searched again next
432  * time we spot it.
433  */
434  path[next_id] = found ? NULL : invalid_path;
435  return found;
436  }
437 
438  /* This node has already been visited => we have a cycle.
439  * Backtrack to find the exact flow. */
440  uint flow = this->FindCycleFlow(path, at_next_pos);
441  if (flow > 0) {
442  this->EliminateCycle(path, at_next_pos, flow);
443  return true;
444  }
445 
446  return false;
447 }
448 
455 {
456  bool cycles_found = false;
457  uint size = this->job.Size();
458  PathVector path(size, NULL);
459  for (NodeID node = 0; node < size; ++node) {
460  /* Starting at each node in the graph find all cycles involving this
461  * node. */
462  std::fill(path.begin(), path.end(), (Path *)NULL);
463  cycles_found |= this->EliminateCycles(path, node, node);
464  }
465  return cycles_found;
466 }
467 
473 {
474  PathVector paths;
475  uint size = job.Size();
476  uint accuracy = job.Settings().accuracy;
477  bool more_loops;
478 
479  do {
480  more_loops = false;
481  for (NodeID source = 0; source < size; ++source) {
482  /* First saturate the shortest paths. */
483  this->Dijkstra<DistanceAnnotation, GraphEdgeIterator>(source, paths);
484 
485  for (NodeID dest = 0; dest < size; ++dest) {
486  Edge edge = job[source][dest];
487  if (edge.UnsatisfiedDemand() > 0) {
488  Path *path = paths[dest];
489  assert(path != NULL);
490  /* Generally only allow paths that don't exceed the
491  * available capacity. But if no demand has been assigned
492  * yet, make an exception and allow any valid path *once*. */
493  if (path->GetFreeCapacity() > 0 && this->PushFlow(edge, path,
494  accuracy, this->max_saturation) > 0) {
495  /* If a path has been found there is a chance we can
496  * find more. */
497  more_loops = more_loops || (edge.UnsatisfiedDemand() > 0);
498  } else if (edge.UnsatisfiedDemand() == edge.Demand() &&
499  path->GetFreeCapacity() > INT_MIN) {
500  this->PushFlow(edge, path, accuracy, UINT_MAX);
501  }
502  }
503  }
504  this->CleanupPaths(source, paths);
505  }
506  } while (more_loops || this->EliminateCycles());
507 }
508 
515 {
516  this->max_saturation = UINT_MAX; // disable artificial cap on saturation
517  PathVector paths;
518  uint size = job.Size();
519  uint accuracy = job.Settings().accuracy;
520  bool demand_left = true;
521  while (demand_left) {
522  demand_left = false;
523  for (NodeID source = 0; source < size; ++source) {
524  this->Dijkstra<CapacityAnnotation, FlowEdgeIterator>(source, paths);
525  for (NodeID dest = 0; dest < size; ++dest) {
526  Edge edge = this->job[source][dest];
527  Path *path = paths[dest];
528  if (edge.UnsatisfiedDemand() > 0 && path->GetFreeCapacity() > INT_MIN) {
529  this->PushFlow(edge, path, accuracy, UINT_MAX);
530  if (edge.UnsatisfiedDemand() > 0) demand_left = true;
531  }
532  }
533  this->CleanupPaths(source, paths);
534  }
535  }
536 }
537 
549 template <typename T>
550 bool Greater(T x_anno, T y_anno, NodeID x, NodeID y)
551 {
552  if (x_anno > y_anno) return true;
553  if (x_anno < y_anno) return false;
554  return x > y;
555 }
556 
564  const CapacityAnnotation *y) const
565 {
566  return x != y && Greater<int>(x->GetAnnotation(), y->GetAnnotation(),
567  x->GetNode(), y->GetNode());
568 }
569 
577  const DistanceAnnotation *y) const
578 {
579  return x != y && !Greater<uint>(x->GetAnnotation(), y->GetAnnotation(),
580  x->GetNode(), y->GetNode());
581 }