Codechange: Lowercase variable names and use _ separator
[openttd-github.git] / src / linkgraph / mcf.cpp
blobc47684053e734d8baf264de1b454392266ecec1e
1 /** @file mcf.cpp Definition of Multi-Commodity-Flow solver. */
3 #include "../stdafx.h"
4 #include "../core/math_func.hpp"
5 #include "../timer/timer_game_tick.h"
6 #include "mcf.h"
8 #include "../safeguards.h"
10 typedef std::map<NodeID, Path *> PathViaMap;
12 /**
13 * Distance-based annotation for use in the Dijkstra algorithm. This is close
14 * to the original meaning of "annotation" in this context. Paths are rated
15 * according to the sum of distances of their edges.
17 class DistanceAnnotation : public Path {
18 public:
20 /**
21 * Constructor.
22 * @param n ID of node to be annotated.
23 * @param source If the node is the source of its path.
25 DistanceAnnotation(NodeID n, bool source = false) : Path(n, source) {}
27 bool IsBetter(const DistanceAnnotation *base, uint cap, int free_cap, uint dist) const;
29 /**
30 * Return the actual value of the annotation, in this case the distance.
31 * @return Distance.
33 inline uint GetAnnotation() const { return this->distance; }
35 /**
36 * Update the cached annotation value
38 inline void UpdateAnnotation() { }
40 /**
41 * Comparator for std containers.
43 struct Comparator {
44 bool operator()(const DistanceAnnotation *x, const DistanceAnnotation *y) const;
48 /**
49 * Capacity-based annotation for use in the Dijkstra algorithm. This annotation
50 * rates paths according to the maximum capacity of their edges. The Dijkstra
51 * algorithm still gives meaningful results like this as the capacity of a path
52 * can only decrease or stay the same if you add more edges.
54 class CapacityAnnotation : public Path {
55 int cached_annotation;
57 public:
59 /**
60 * Constructor.
61 * @param n ID of node to be annotated.
62 * @param source If the node is the source of its path.
64 CapacityAnnotation(NodeID n, bool source = false) : Path(n, source) {}
66 bool IsBetter(const CapacityAnnotation *base, uint cap, int free_cap, uint dist) const;
68 /**
69 * Return the actual value of the annotation, in this case the capacity.
70 * @return Capacity.
72 inline int GetAnnotation() const { return this->cached_annotation; }
74 /**
75 * Update the cached annotation value
77 inline void UpdateAnnotation()
79 this->cached_annotation = this->GetCapacityRatio();
82 /**
83 * Comparator for std containers.
85 struct Comparator {
86 bool operator()(const CapacityAnnotation *x, const CapacityAnnotation *y) const;
90 /**
91 * Iterator class for getting the edges in the order of their next_edge
92 * members.
94 class GraphEdgeIterator {
95 private:
96 LinkGraphJob &job; ///< Job being executed
98 std::vector<LinkGraphJob::EdgeAnnotation>::const_iterator i; ///< Iterator pointing to current edge.
99 std::vector<LinkGraphJob::EdgeAnnotation>::const_iterator end; ///< Iterator pointing beyond last edge.
101 public:
104 * Construct a GraphEdgeIterator.
105 * @param job Job to iterate on.
107 GraphEdgeIterator(LinkGraphJob &job) : job(job), i(), end() {}
110 * Setup the node to start iterating at.
111 * @param node Node to start iterating at.
113 void SetNode(NodeID, NodeID node)
115 this->i = this->job[node].edges.cbegin();
116 this->end = this->job[node].edges.cend();
120 * Retrieve the ID of the node the next edge points to.
121 * @return Next edge's target node ID or INVALID_NODE.
123 NodeID Next()
125 return this->i != this->end ? (this->i++)->base.dest_node : INVALID_NODE;
130 * Iterator class for getting edges from a FlowStatMap.
132 class FlowEdgeIterator {
133 private:
134 LinkGraphJob &job; ///< Link graph job we're working with.
136 /** Lookup table for getting NodeIDs from StationIDs. */
137 std::vector<NodeID> station_to_node;
139 /** Current iterator in the shares map. */
140 FlowStat::SharesMap::const_iterator it;
142 /** End of the shares map. */
143 FlowStat::SharesMap::const_iterator end;
144 public:
147 * Constructor.
148 * @param job Link graph job to work with.
150 FlowEdgeIterator(LinkGraphJob &job) : job(job)
152 for (NodeID i = 0; i < job.Size(); ++i) {
153 StationID st = job[i].base.station;
154 if (st >= this->station_to_node.size()) {
155 this->station_to_node.resize(st + 1);
157 this->station_to_node[st] = i;
162 * Setup the node to retrieve edges from.
163 * @param source Root of the current path tree.
164 * @param node Current node to be checked for outgoing flows.
166 void SetNode(NodeID source, NodeID node)
168 const FlowStatMap &flows = this->job[node].flows;
169 FlowStatMap::const_iterator it = flows.find(this->job[source].base.station);
170 if (it != flows.end()) {
171 this->it = it->second.GetShares()->begin();
172 this->end = it->second.GetShares()->end();
173 } else {
174 this->it = FlowStat::empty_sharesmap.begin();
175 this->end = FlowStat::empty_sharesmap.end();
180 * Get the next node for which a flow exists.
181 * @return ID of next node with flow.
183 NodeID Next()
185 if (this->it == this->end) return INVALID_NODE;
186 return this->station_to_node[(this->it++)->second];
191 * Determines if an extension to the given Path with the given parameters is
192 * better than this path.
193 * @param base Other path.
194 * @param free_cap Capacity of the new edge to be added to base.
195 * @param dist Distance of the new edge.
196 * @return True if base + the new edge would be better than the path associated
197 * with this annotation.
199 bool DistanceAnnotation::IsBetter(const DistanceAnnotation *base, uint,
200 int free_cap, uint dist) const
202 /* If any of the paths is disconnected, the other one is better. If both
203 * are disconnected, this path is better.*/
204 if (base->distance == UINT_MAX) {
205 return false;
206 } else if (this->distance == UINT_MAX) {
207 return true;
210 if (free_cap > 0 && base->free_capacity > 0) {
211 /* If both paths have capacity left, compare their distances.
212 * If the other path has capacity left and this one hasn't, the
213 * other one's better (thus, return true). */
214 return this->free_capacity > 0 ? (base->distance + dist < this->distance) : true;
215 } else {
216 /* If the other path doesn't have capacity left, but this one has,
217 * the other one is worse (thus, return false).
218 * If both paths are out of capacity, do the regular distance
219 * comparison. */
220 return this->free_capacity > 0 ? false : (base->distance + dist < this->distance);
225 * Determines if an extension to the given Path with the given parameters is
226 * better than this path.
227 * @param base Other path.
228 * @param free_cap Capacity of the new edge to be added to base.
229 * @param dist Distance of the new edge.
230 * @return True if base + the new edge would be better than the path associated
231 * with this annotation.
233 bool CapacityAnnotation::IsBetter(const CapacityAnnotation *base, uint cap,
234 int free_cap, uint dist) const
236 int min_cap = Path::GetCapacityRatio(std::min(base->free_capacity, free_cap), std::min(base->capacity, cap));
237 int this_cap = this->GetCapacityRatio();
238 if (min_cap == this_cap) {
239 /* If the capacities are the same and the other path isn't disconnected
240 * choose the shorter path. */
241 return base->distance == UINT_MAX ? false : (base->distance + dist < this->distance);
242 } else {
243 return min_cap > this_cap;
248 * A slightly modified Dijkstra algorithm. Grades the paths not necessarily by
249 * distance, but by the value Tannotation computes. It uses the max_saturation
250 * setting to artificially decrease capacities.
251 * @tparam Tannotation Annotation to be used.
252 * @tparam Tedge_iterator Iterator to be used for getting outgoing edges.
253 * @param source_node Node where the algorithm starts.
254 * @param paths Container for the paths to be calculated.
256 template <class Tannotation, class Tedge_iterator>
257 void MultiCommodityFlow::Dijkstra(NodeID source_node, PathVector &paths)
259 typedef std::set<Tannotation *, typename Tannotation::Comparator> AnnoSet;
260 Tedge_iterator iter(this->job);
261 uint16_t size = this->job.Size();
262 AnnoSet annos;
263 paths.resize(size, nullptr);
264 for (NodeID node = 0; node < size; ++node) {
265 Tannotation *anno = new Tannotation(node, node == source_node);
266 anno->UpdateAnnotation();
267 annos.insert(anno);
268 paths[node] = anno;
270 while (!annos.empty()) {
271 typename AnnoSet::iterator i = annos.begin();
272 Tannotation *source = *i;
273 annos.erase(i);
274 NodeID from = source->GetNode();
275 iter.SetNode(source_node, from);
276 for (NodeID to = iter.Next(); to != INVALID_NODE; to = iter.Next()) {
277 if (to == from) continue; // Not a real edge but a consumption sign.
278 const Edge &edge = this->job[from][to];
279 uint capacity = edge.base.capacity;
280 if (this->max_saturation != UINT_MAX) {
281 capacity *= this->max_saturation;
282 capacity /= 100;
283 if (capacity == 0) capacity = 1;
285 /* Prioritize the fastest route for passengers, mail and express cargo,
286 * and the shortest route for other classes of cargo.
287 * In-between stops are punished with a 1 tile or 1 day penalty. */
288 bool express = IsCargoInClass(this->job.Cargo(), CC_PASSENGERS) ||
289 IsCargoInClass(this->job.Cargo(), CC_MAIL) ||
290 IsCargoInClass(this->job.Cargo(), CC_EXPRESS);
291 uint distance = DistanceMaxPlusManhattan(this->job[from].base.xy, this->job[to].base.xy) + 1;
292 /* Compute a default travel time from the distance and an average speed of 1 tile/day. */
293 uint time = (edge.base.TravelTime() != 0) ? edge.base.TravelTime() + Ticks::DAY_TICKS : distance * Ticks::DAY_TICKS;
294 uint distance_anno = express ? time : distance;
296 Tannotation *dest = static_cast<Tannotation *>(paths[to]);
297 if (dest->IsBetter(source, capacity, capacity - edge.Flow(), distance_anno)) {
298 annos.erase(dest);
299 dest->Fork(source, capacity, capacity - edge.Flow(), distance_anno);
300 dest->UpdateAnnotation();
301 annos.insert(dest);
308 * Clean up paths that lead nowhere and the root path.
309 * @param source_id ID of the root node.
310 * @param paths Paths to be cleaned up.
312 void MultiCommodityFlow::CleanupPaths(NodeID source_id, PathVector &paths)
314 Path *source = paths[source_id];
315 paths[source_id] = nullptr;
316 for (PathVector::iterator i = paths.begin(); i != paths.end(); ++i) {
317 Path *path = *i;
318 if (path == nullptr) continue;
319 if (path->GetParent() == source) path->Detach();
320 while (path != source && path != nullptr && path->GetFlow() == 0) {
321 Path *parent = path->GetParent();
322 path->Detach();
323 if (path->GetNumChildren() == 0) {
324 paths[path->GetNode()] = nullptr;
325 delete path;
327 path = parent;
330 delete source;
331 paths.clear();
335 * Push flow along a path and update the unsatisfied_demand of the associated
336 * edge.
337 * @param node Node where the path starts.
338 * @param to Node where the path ends.
339 * @param path End of the path the flow should be pushed on.
340 * @param accuracy Accuracy of the calculation.
341 * @param max_saturation If < UINT_MAX only push flow up to the given
342 * saturation, otherwise the path can be "overloaded".
344 uint MultiCommodityFlow::PushFlow(Node &node, NodeID to, Path *path, uint accuracy,
345 uint max_saturation)
347 assert(node.UnsatisfiedDemandTo(to) > 0);
348 uint flow = Clamp(node.DemandTo(to) / accuracy, 1, node.UnsatisfiedDemandTo(to));
349 flow = path->AddFlow(flow, this->job, max_saturation);
350 node.SatisfyDemandTo(to, flow);
351 return flow;
355 * Find the flow along a cycle including cycle_begin in path.
356 * @param path Set of paths that form the cycle.
357 * @param cycle_begin Path to start at.
358 * @return Flow along the cycle.
360 uint MCF1stPass::FindCycleFlow(const PathVector &path, const Path *cycle_begin)
362 uint flow = UINT_MAX;
363 const Path *cycle_end = cycle_begin;
364 do {
365 flow = std::min(flow, cycle_begin->GetFlow());
366 cycle_begin = path[cycle_begin->GetNode()];
367 } while (cycle_begin != cycle_end);
368 return flow;
372 * Eliminate a cycle of the given flow in the given set of paths.
373 * @param path Set of paths containing the cycle.
374 * @param cycle_begin Part of the cycle to start at.
375 * @param flow Flow along the cycle.
377 void MCF1stPass::EliminateCycle(PathVector &path, Path *cycle_begin, uint flow)
379 Path *cycle_end = cycle_begin;
380 do {
381 NodeID prev = cycle_begin->GetNode();
382 cycle_begin->ReduceFlow(flow);
383 if (cycle_begin->GetFlow() == 0) {
384 PathList &node_paths = this->job[cycle_begin->GetParent()->GetNode()].paths;
385 for (PathList::iterator i = node_paths.begin(); i != node_paths.end(); ++i) {
386 if (*i == cycle_begin) {
387 node_paths.erase(i);
388 node_paths.push_back(cycle_begin);
389 break;
393 cycle_begin = path[prev];
394 Edge &edge = this->job[prev][cycle_begin->GetNode()];
395 edge.RemoveFlow(flow);
396 } while (cycle_begin != cycle_end);
400 * Eliminate cycles for origin_id in the graph. Start searching at next_id and
401 * work recursively. Also "summarize" paths: Add up the flows along parallel
402 * paths in one.
403 * @param path Paths checked in parent calls to this method.
404 * @param origin_id Origin of the paths to be checked.
405 * @param next_id Next node to be checked.
406 * @return If any cycles have been found and eliminated.
408 bool MCF1stPass::EliminateCycles(PathVector &path, NodeID origin_id, NodeID next_id)
410 Path *at_next_pos = path[next_id];
412 /* this node has already been searched */
413 if (at_next_pos == Path::invalid_path) return false;
415 if (at_next_pos == nullptr) {
416 /* Summarize paths; add up the paths with the same source and next hop
417 * in one path each. */
418 PathList &paths = this->job[next_id].paths;
419 PathViaMap next_hops;
420 for (PathList::iterator i = paths.begin(); i != paths.end();) {
421 Path *new_child = *i;
422 uint new_flow = new_child->GetFlow();
423 if (new_flow == 0) break;
424 if (new_child->GetOrigin() == origin_id) {
425 PathViaMap::iterator via_it = next_hops.find(new_child->GetNode());
426 if (via_it == next_hops.end()) {
427 next_hops[new_child->GetNode()] = new_child;
428 ++i;
429 } else {
430 Path *child = via_it->second;
431 child->AddFlow(new_flow);
432 new_child->ReduceFlow(new_flow);
434 /* We might hit end() with with the ++ here and skip the
435 * newly push_back'ed path. That's good as the flow of that
436 * path is 0 anyway. */
437 paths.erase(i++);
438 paths.push_back(new_child);
440 } else {
441 ++i;
444 bool found = false;
445 /* Search the next hops for nodes we have already visited */
446 for (PathViaMap::iterator via_it = next_hops.begin();
447 via_it != next_hops.end(); ++via_it) {
448 Path *child = via_it->second;
449 if (child->GetFlow() > 0) {
450 /* Push one child into the path vector and search this child's
451 * children. */
452 path[next_id] = child;
453 found = this->EliminateCycles(path, origin_id, child->GetNode()) || found;
456 /* All paths departing from this node have been searched. Mark as
457 * resolved if no cycles found. If cycles were found further cycles
458 * could be found in this branch, thus it has to be searched again next
459 * time we spot it.
461 path[next_id] = found ? nullptr : Path::invalid_path;
462 return found;
465 /* This node has already been visited => we have a cycle.
466 * Backtrack to find the exact flow. */
467 uint flow = this->FindCycleFlow(path, at_next_pos);
468 if (flow > 0) {
469 this->EliminateCycle(path, at_next_pos, flow);
470 return true;
473 return false;
477 * Eliminate all cycles in the graph. Check paths starting at each node for
478 * potential cycles.
479 * @return If any cycles have been found and eliminated.
481 bool MCF1stPass::EliminateCycles()
483 bool cycles_found = false;
484 uint16_t size = this->job.Size();
485 PathVector path(size, nullptr);
486 for (NodeID node = 0; node < size; ++node) {
487 /* Starting at each node in the graph find all cycles involving this
488 * node. */
489 std::fill(path.begin(), path.end(), (Path *)nullptr);
490 cycles_found |= this->EliminateCycles(path, node, node);
492 return cycles_found;
496 * Run the first pass of the MCF calculation.
497 * @param job Link graph job to calculate.
499 MCF1stPass::MCF1stPass(LinkGraphJob &job) : MultiCommodityFlow(job)
501 PathVector paths;
502 uint16_t size = job.Size();
503 uint accuracy = job.Settings().accuracy;
504 bool more_loops;
505 std::vector<bool> finished_sources(size);
507 do {
508 more_loops = false;
509 for (NodeID source = 0; source < size; ++source) {
510 if (finished_sources[source]) continue;
512 /* First saturate the shortest paths. */
513 this->Dijkstra<DistanceAnnotation, GraphEdgeIterator>(source, paths);
515 Node &src_node = job[source];
516 bool source_demand_left = false;
517 for (NodeID dest = 0; dest < size; ++dest) {
518 if (src_node.UnsatisfiedDemandTo(dest) > 0) {
519 Path *path = paths[dest];
520 assert(path != nullptr);
521 /* Generally only allow paths that don't exceed the
522 * available capacity. But if no demand has been assigned
523 * yet, make an exception and allow any valid path *once*. */
524 if (path->GetFreeCapacity() > 0 && this->PushFlow(src_node, dest, path,
525 accuracy, this->max_saturation) > 0) {
526 /* If a path has been found there is a chance we can
527 * find more. */
528 more_loops = more_loops || (src_node.UnsatisfiedDemandTo(dest) > 0);
529 } else if (src_node.UnsatisfiedDemandTo(dest) == src_node.DemandTo(dest) &&
530 path->GetFreeCapacity() > INT_MIN) {
531 this->PushFlow(src_node, dest, path, accuracy, UINT_MAX);
533 if (src_node.UnsatisfiedDemandTo(dest) > 0) source_demand_left = true;
536 finished_sources[source] = !source_demand_left;
537 this->CleanupPaths(source, paths);
539 } while ((more_loops || this->EliminateCycles()) && !job.IsJobAborted());
543 * Run the second pass of the MCF calculation which assigns all remaining
544 * demands to existing paths.
545 * @param job Link graph job to calculate.
547 MCF2ndPass::MCF2ndPass(LinkGraphJob &job) : MultiCommodityFlow(job)
549 this->max_saturation = UINT_MAX; // disable artificial cap on saturation
550 PathVector paths;
551 uint16_t size = job.Size();
552 uint accuracy = job.Settings().accuracy;
553 bool demand_left = true;
554 std::vector<bool> finished_sources(size);
555 while (demand_left && !job.IsJobAborted()) {
556 demand_left = false;
557 for (NodeID source = 0; source < size; ++source) {
558 if (finished_sources[source]) continue;
560 this->Dijkstra<CapacityAnnotation, FlowEdgeIterator>(source, paths);
562 Node &src_node = job[source];
563 bool source_demand_left = false;
564 for (NodeID dest = 0; dest < size; ++dest) {
565 Path *path = paths[dest];
566 if (src_node.UnsatisfiedDemandTo(dest) > 0 && path->GetFreeCapacity() > INT_MIN) {
567 this->PushFlow(src_node, dest, path, accuracy, UINT_MAX);
568 if (src_node.UnsatisfiedDemandTo(dest) > 0) {
569 demand_left = true;
570 source_demand_left = true;
574 finished_sources[source] = !source_demand_left;
575 this->CleanupPaths(source, paths);
581 * Relation that creates a weak order without duplicates.
582 * Avoid accidentally deleting different paths of the same capacity/distance in
583 * a set. When the annotation is the same node IDs are compared, so there are
584 * no equal ranges.
585 * @tparam T Type to be compared on.
586 * @param x_anno First value.
587 * @param y_anno Second value.
588 * @param x Node id associated with the first value.
589 * @param y Node id associated with the second value.
591 template <typename T>
592 bool Greater(T x_anno, T y_anno, NodeID x, NodeID y)
594 if (x_anno > y_anno) return true;
595 if (x_anno < y_anno) return false;
596 return x > y;
600 * Compare two capacity annotations.
601 * @param x First capacity annotation.
602 * @param y Second capacity annotation.
603 * @return If x is better than y.
605 bool CapacityAnnotation::Comparator::operator()(const CapacityAnnotation *x,
606 const CapacityAnnotation *y) const
608 return x != y && Greater<int>(x->GetAnnotation(), y->GetAnnotation(),
609 x->GetNode(), y->GetNode());
613 * Compare two distance annotations.
614 * @param x First distance annotation.
615 * @param y Second distance annotation.
616 * @return If x is better than y.
618 bool DistanceAnnotation::Comparator::operator()(const DistanceAnnotation *x,
619 const DistanceAnnotation *y) const
621 return x != y && !Greater<uint>(x->GetAnnotation(), y->GetAnnotation(),
622 x->GetNode(), y->GetNode());