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  inline void UpdateAnnotation() { }
39 
43  struct Comparator {
44  bool operator()(const DistanceAnnotation *x, const DistanceAnnotation *y) const;
45  };
46 };
47 
54 class CapacityAnnotation : public Path {
55  int cached_annotation;
56 
57 public:
58 
64  CapacityAnnotation(NodeID n, bool source = false) : Path(n, source) {}
65 
66  bool IsBetter(const CapacityAnnotation *base, uint cap, int free_cap, uint dist) const;
67 
72  inline int GetAnnotation() const { return this->cached_annotation; }
73 
77  inline void UpdateAnnotation()
78  {
79  this->cached_annotation = this->GetCapacityRatio();
80  }
81 
85  struct Comparator {
86  bool operator()(const CapacityAnnotation *x, const CapacityAnnotation *y) const;
87  };
88 };
89 
95 private:
99 
100 public:
101 
107  i(NULL, NULL, INVALID_NODE), end(NULL, NULL, INVALID_NODE)
108  {}
109 
115  void SetNode(NodeID source, NodeID node)
116  {
117  this->i = this->job[node].Begin();
118  this->end = this->job[node].End();
119  }
120 
125  NodeID Next()
126  {
127  return this->i != this->end ? (this->i++)->first : INVALID_NODE;
128  }
129 };
130 
135 private:
137 
139  std::vector<NodeID> station_to_node;
140 
142  FlowStat::SharesMap::const_iterator it;
143 
145  FlowStat::SharesMap::const_iterator end;
146 public:
147 
153  {
154  for (NodeID i = 0; i < job.Size(); ++i) {
155  StationID st = job[i].Station();
156  if (st >= this->station_to_node.size()) {
157  this->station_to_node.resize(st + 1);
158  }
159  this->station_to_node[st] = i;
160  }
161  }
162 
168  void SetNode(NodeID source, NodeID node)
169  {
170  const FlowStatMap &flows = this->job[node].Flows();
171  FlowStatMap::const_iterator it = flows.find(this->job[source].Station());
172  if (it != flows.end()) {
173  this->it = it->second.GetShares()->begin();
174  this->end = it->second.GetShares()->end();
175  } else {
176  this->it = FlowStat::empty_sharesmap.begin();
177  this->end = FlowStat::empty_sharesmap.end();
178  }
179  }
180 
185  NodeID Next()
186  {
187  if (this->it == this->end) return INVALID_NODE;
188  return this->station_to_node[(this->it++)->second];
189  }
190 };
191 
202  int free_cap, uint dist) const
203 {
204  /* If any of the paths is disconnected, the other one is better. If both
205  * are disconnected, this path is better.*/
206  if (base->distance == UINT_MAX) {
207  return false;
208  } else if (this->distance == UINT_MAX) {
209  return true;
210  }
211 
212  if (free_cap > 0 && base->free_capacity > 0) {
213  /* If both paths have capacity left, compare their distances.
214  * If the other path has capacity left and this one hasn't, the
215  * other one's better (thus, return true). */
216  return this->free_capacity > 0 ? (base->distance + dist < this->distance) : true;
217  } else {
218  /* If the other path doesn't have capacity left, but this one has,
219  * the other one is worse (thus, return false).
220  * If both paths are out of capacity, do the regular distance
221  * comparison. */
222  return this->free_capacity > 0 ? false : (base->distance + dist < this->distance);
223  }
224 }
225 
236  int free_cap, uint dist) const
237 {
238  int min_cap = Path::GetCapacityRatio(min(base->free_capacity, free_cap), min(base->capacity, cap));
239  int this_cap = this->GetCapacityRatio();
240  if (min_cap == this_cap) {
241  /* If the capacities are the same and the other path isn't disconnected
242  * choose the shorter path. */
243  return base->distance == UINT_MAX ? false : (base->distance + dist < this->distance);
244  } else {
245  return min_cap > this_cap;
246  }
247 }
248 
258 template<class Tannotation, class Tedge_iterator>
259 void MultiCommodityFlow::Dijkstra(NodeID source_node, PathVector &paths)
260 {
261  typedef std::set<Tannotation *, typename Tannotation::Comparator> AnnoSet;
262  Tedge_iterator iter(this->job);
263  uint size = this->job.Size();
264  AnnoSet annos;
265  paths.resize(size, NULL);
266  for (NodeID node = 0; node < size; ++node) {
267  Tannotation *anno = new Tannotation(node, node == source_node);
268  anno->UpdateAnnotation();
269  annos.insert(anno);
270  paths[node] = anno;
271  }
272  while (!annos.empty()) {
273  typename AnnoSet::iterator i = annos.begin();
274  Tannotation *source = *i;
275  annos.erase(i);
276  NodeID from = source->GetNode();
277  iter.SetNode(source_node, from);
278  for (NodeID to = iter.Next(); to != INVALID_NODE; to = iter.Next()) {
279  if (to == from) continue; // Not a real edge but a consumption sign.
280  Edge edge = this->job[from][to];
281  uint capacity = edge.Capacity();
282  if (this->max_saturation != UINT_MAX) {
283  capacity *= this->max_saturation;
284  capacity /= 100;
285  if (capacity == 0) capacity = 1;
286  }
287  /* punish in-between stops a little */
288  uint distance = DistanceMaxPlusManhattan(this->job[from].XY(), this->job[to].XY()) + 1;
289  Tannotation *dest = static_cast<Tannotation *>(paths[to]);
290  if (dest->IsBetter(source, capacity, capacity - edge.Flow(), distance)) {
291  annos.erase(dest);
292  dest->Fork(source, capacity, capacity - edge.Flow(), distance);
293  dest->UpdateAnnotation();
294  annos.insert(dest);
295  }
296  }
297  }
298 }
299 
305 void MultiCommodityFlow::CleanupPaths(NodeID source_id, PathVector &paths)
306 {
307  Path *source = paths[source_id];
308  paths[source_id] = NULL;
309  for (PathVector::iterator i = paths.begin(); i != paths.end(); ++i) {
310  Path *path = *i;
311  if (path == NULL) continue;
312  if (path->GetParent() == source) path->Detach();
313  while (path != source && path != NULL && path->GetFlow() == 0) {
314  Path *parent = path->GetParent();
315  path->Detach();
316  if (path->GetNumChildren() == 0) {
317  paths[path->GetNode()] = NULL;
318  delete path;
319  }
320  path = parent;
321  }
322  }
323  delete source;
324  paths.clear();
325 }
326 
336 uint MultiCommodityFlow::PushFlow(Edge &edge, Path *path, uint accuracy,
337  uint max_saturation)
338 {
339  assert(edge.UnsatisfiedDemand() > 0);
340  uint flow = Clamp(edge.Demand() / accuracy, 1, edge.UnsatisfiedDemand());
341  flow = path->AddFlow(flow, this->job, max_saturation);
342  edge.SatisfyDemand(flow);
343  return flow;
344 }
345 
352 uint MCF1stPass::FindCycleFlow(const PathVector &path, const Path *cycle_begin)
353 {
354  uint flow = UINT_MAX;
355  const Path *cycle_end = cycle_begin;
356  do {
357  flow = min(flow, cycle_begin->GetFlow());
358  cycle_begin = path[cycle_begin->GetNode()];
359  } while (cycle_begin != cycle_end);
360  return flow;
361 }
362 
369 void MCF1stPass::EliminateCycle(PathVector &path, Path *cycle_begin, uint flow)
370 {
371  Path *cycle_end = cycle_begin;
372  do {
373  NodeID prev = cycle_begin->GetNode();
374  cycle_begin->ReduceFlow(flow);
375  if (cycle_begin->GetFlow() == 0) {
376  PathList &node_paths = this->job[cycle_begin->GetParent()->GetNode()].Paths();
377  for (PathList::iterator i = node_paths.begin(); i != node_paths.end(); ++i) {
378  if (*i == cycle_begin) {
379  node_paths.erase(i);
380  node_paths.push_back(cycle_begin);
381  break;
382  }
383  }
384  }
385  cycle_begin = path[prev];
386  Edge edge = this->job[prev][cycle_begin->GetNode()];
387  edge.RemoveFlow(flow);
388  } while (cycle_begin != cycle_end);
389 }
390 
400 bool MCF1stPass::EliminateCycles(PathVector &path, NodeID origin_id, NodeID next_id)
401 {
402  Path *at_next_pos = path[next_id];
403 
404  /* this node has already been searched */
405  if (at_next_pos == Path::invalid_path) return false;
406 
407  if (at_next_pos == NULL) {
408  /* Summarize paths; add up the paths with the same source and next hop
409  * in one path each. */
410  PathList &paths = this->job[next_id].Paths();
411  PathViaMap next_hops;
412  for (PathList::iterator i = paths.begin(); i != paths.end();) {
413  Path *new_child = *i;
414  uint new_flow = new_child->GetFlow();
415  if (new_flow == 0) break;
416  if (new_child->GetOrigin() == origin_id) {
417  PathViaMap::iterator via_it = next_hops.find(new_child->GetNode());
418  if (via_it == next_hops.end()) {
419  next_hops[new_child->GetNode()] = new_child;
420  ++i;
421  } else {
422  Path *child = via_it->second;
423  child->AddFlow(new_flow);
424  new_child->ReduceFlow(new_flow);
425 
426  /* We might hit end() with with the ++ here and skip the
427  * newly push_back'ed path. That's good as the flow of that
428  * path is 0 anyway. */
429  paths.erase(i++);
430  paths.push_back(new_child);
431  }
432  } else {
433  ++i;
434  }
435  }
436  bool found = false;
437  /* Search the next hops for nodes we have already visited */
438  for (PathViaMap::iterator via_it = next_hops.begin();
439  via_it != next_hops.end(); ++via_it) {
440  Path *child = via_it->second;
441  if (child->GetFlow() > 0) {
442  /* Push one child into the path vector and search this child's
443  * children. */
444  path[next_id] = child;
445  found = this->EliminateCycles(path, origin_id, child->GetNode()) || found;
446  }
447  }
448  /* All paths departing from this node have been searched. Mark as
449  * resolved if no cycles found. If cycles were found further cycles
450  * could be found in this branch, thus it has to be searched again next
451  * time we spot it.
452  */
453  path[next_id] = found ? NULL : Path::invalid_path;
454  return found;
455  }
456 
457  /* This node has already been visited => we have a cycle.
458  * Backtrack to find the exact flow. */
459  uint flow = this->FindCycleFlow(path, at_next_pos);
460  if (flow > 0) {
461  this->EliminateCycle(path, at_next_pos, flow);
462  return true;
463  }
464 
465  return false;
466 }
467 
474 {
475  bool cycles_found = false;
476  uint size = this->job.Size();
477  PathVector path(size, NULL);
478  for (NodeID node = 0; node < size; ++node) {
479  /* Starting at each node in the graph find all cycles involving this
480  * node. */
481  std::fill(path.begin(), path.end(), (Path *)NULL);
482  cycles_found |= this->EliminateCycles(path, node, node);
483  }
484  return cycles_found;
485 }
486 
492 {
493  PathVector paths;
494  uint size = job.Size();
495  uint accuracy = job.Settings().accuracy;
496  bool more_loops;
497 
498  do {
499  more_loops = false;
500  for (NodeID source = 0; source < size; ++source) {
501  /* First saturate the shortest paths. */
502  this->Dijkstra<DistanceAnnotation, GraphEdgeIterator>(source, paths);
503 
504  for (NodeID dest = 0; dest < size; ++dest) {
505  Edge edge = job[source][dest];
506  if (edge.UnsatisfiedDemand() > 0) {
507  Path *path = paths[dest];
508  assert(path != NULL);
509  /* Generally only allow paths that don't exceed the
510  * available capacity. But if no demand has been assigned
511  * yet, make an exception and allow any valid path *once*. */
512  if (path->GetFreeCapacity() > 0 && this->PushFlow(edge, path,
513  accuracy, this->max_saturation) > 0) {
514  /* If a path has been found there is a chance we can
515  * find more. */
516  more_loops = more_loops || (edge.UnsatisfiedDemand() > 0);
517  } else if (edge.UnsatisfiedDemand() == edge.Demand() &&
518  path->GetFreeCapacity() > INT_MIN) {
519  this->PushFlow(edge, path, accuracy, UINT_MAX);
520  }
521  }
522  }
523  this->CleanupPaths(source, paths);
524  }
525  } while (more_loops || this->EliminateCycles());
526 }
527 
534 {
535  this->max_saturation = UINT_MAX; // disable artificial cap on saturation
536  PathVector paths;
537  uint size = job.Size();
538  uint accuracy = job.Settings().accuracy;
539  bool demand_left = true;
540  while (demand_left) {
541  demand_left = false;
542  for (NodeID source = 0; source < size; ++source) {
543  this->Dijkstra<CapacityAnnotation, FlowEdgeIterator>(source, paths);
544  for (NodeID dest = 0; dest < size; ++dest) {
545  Edge edge = this->job[source][dest];
546  Path *path = paths[dest];
547  if (edge.UnsatisfiedDemand() > 0 && path->GetFreeCapacity() > INT_MIN) {
548  this->PushFlow(edge, path, accuracy, UINT_MAX);
549  if (edge.UnsatisfiedDemand() > 0) demand_left = true;
550  }
551  }
552  this->CleanupPaths(source, paths);
553  }
554  }
555 }
556 
568 template <typename T>
569 bool Greater(T x_anno, T y_anno, NodeID x, NodeID y)
570 {
571  if (x_anno > y_anno) return true;
572  if (x_anno < y_anno) return false;
573  return x > y;
574 }
575 
583  const CapacityAnnotation *y) const
584 {
585  return x != y && Greater<int>(x->GetAnnotation(), y->GetAnnotation(),
586  x->GetNode(), y->GetNode());
587 }
588 
596  const DistanceAnnotation *y) const
597 {
598  return x != y && !Greater<uint>(x->GetAnnotation(), y->GetAnnotation(),
599  x->GetNode(), y->GetNode());
600 }