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