# linkgraph.cpp

Go to the documentation of this file.

    00001 /* $Id$ */
    00002
    00003 /*
    00004  * This file is part of OpenTTD.
    00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
    00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
    00008  */
    00009
    00012 #include "linkgraph.h"
    00013 #include "demands.h"
    00014 #include "mcf.h"
    00015 #include "flowmapper.h"
    00016 #include "../map_func.h"
    00017 #include "../core/bitmath_func.hpp"
    00018 #include "../debug.h"
    00019 #include "../window_func.h"
    00020 #include "../window_gui.h"
    00021 #include "../moving_average.h"
    00022 #include <queue>
    00023
    00027 LinkGraph _link_graphs[NUM_CARGO];
    00028
    00032 LinkGraphJob::HandlerList LinkGraphJob::_handlers;
    00033
    00040 void Node::Init(StationID st, uint sup, uint dem)
    00041 {
    00042   this->supply = sup;
    00043   this->undelivered_supply = sup;
    00044   this->demand = dem;
    00045   this->station = st;
    00046
    00047   for (PathSet::iterator i = this->paths.begin(); i != this->paths.end(); ++i) {
    00048     delete (*i);
    00049   }
    00050   this->paths.clear();
    00051   this->flows.clear();
    00052 }
    00053
    00059 FORCEINLINE void Edge::Init(uint distance, uint capacity)
    00060 {
    00061   this->distance = distance;
    00062   this->capacity = capacity;
    00063   this->demand = 0;
    00064   this->unsatisfied_demand = 0;
    00065   this->flow = 0;
    00066   this->next_edge =INVALID_NODE;
    00067 }
    00068
    00075 void LinkGraph::CreateComponent(Station *first)
    00076 {
    00077   std::map<Station *, NodeID> index;
    00078   index[first] = this->AddNode(first);
    00079
    00080   std::queue<Station *> search_queue;
    00081   search_queue.push(first);
    00082
    00083   /* find all stations belonging to the current component */
    00084   while(!search_queue.empty()) {
    00085     Station *source = search_queue.front();
    00086     search_queue.pop();
    00087
    00088     const LinkStatMap &links = source->goods[this->cargo].link_stats;
    00089     for(LinkStatMap::const_iterator i = links.begin(); i != links.end(); ++i) {
    00090       Station *target = Station::GetIfValid(i->first);
    00091       if (target == NULL) continue;
    00092
    00093       std::map<Station *, NodeID>::iterator index_it = index.find(target);
    00094       if (index_it == index.end()) {
    00095         search_queue.push(target);
    00096         NodeID node = this->AddNode(target);
    00097         index[target] = node;
    00098
    00099         this->AddEdge(index[source], node,  i->second.Capacity());
    00100       } else {
    00101         this->AddEdge(index[source], index_it->second,  i->second.Capacity());
    00102       }
    00103     }
    00104   }
    00105
    00106   /* here the list of nodes and edges for this component is complete. */
    00107   this->SpawnThread();
    00108 }
    00109
    00123 void LinkGraph::NextComponent()
    00124 {
    00125   /* Check for no stations to avoid problems with Station::GetPoolSize()
    00126    * being 0 later and to avoid searching an empty pool.
    00127    */
    00128   if (Station::GetNumItems() == 0) return;
    00129
    00130   /* Don't mess with running jobs (might happen when changing interval).*/
    00131   if (this->GetSize() > 0) return;
    00132
    00133   /* The station pool may shrink when saving and subsequently loading a game as
    00134    * NULL entries at the end are cut off then. If the current station id points
    00135    * to one of those NULL entries we have to clamp it here to avoid an infinite
    00136    * loop later.
    00137    */
    00138   StationID last_station_id = min(this->current_station_id, Station::GetPoolSize() - 1);
    00139   LinkGraphComponentID current_component_id = this->LinkGraphComponent::index;
    00140
    00141   do {
    00142     if (++this->current_station_id >= Station::GetPoolSize()) {
    00143       /* Wrap around and recycle the component IDs. Use different
    00144        * divisibility by 2 than in the last run so that we can find out
    00145        * which stations haven't been seen in this run.
    00146        */
    00147       this->current_station_id = 0;
    00148       if (current_component_id % 2 == 0) {
    00149         current_component_id = 1;
    00150       } else {
    00151         current_component_id = 0;
    00152       }
    00153     }
    00154
    00155     /* find first station of next component */
    00156     Station *station = Station::GetIfValid(this->current_station_id);
    00157     if (station != NULL) {
    00158       GoodsEntry &ge = station->goods[this->cargo];
    00159       if (ge.last_component == INVALID_LINKGRAPH_COMPONENT ||
    00160           (ge.last_component + current_component_id) % 2 != 0) {
    00161         /* Different divisibility by 2: This station has not been seen
    00162          * in the current run over the link graph.
    00163          */
    00164
    00165         if (!ge.link_stats.empty()) {
    00166           this->LinkGraphComponent::Init(current_component_id + 2);
    00167           CreateComponent(station);
    00168           return;
    00169         }
    00170       }
    00171     }
    00172
    00173   } while (this->current_station_id != last_station_id);
    00174 }
    00175
    00181 void OnTick_LinkGraph()
    00182 {
    00183   if (_date_fract == LinkGraph::COMPONENTS_SPAWN_TICK ||
    00184       _date_fract == LinkGraph::COMPONENTS_JOIN_TICK) {
    00185
    00186     /* This creates a fair distribution of all link graphs' turns over
    00187      * the available dates.
    00188      */
    00189     for (uint cargo = _date % _settings_game.linkgraph.recalc_interval; cargo < NUM_CARGO;
    00190         cargo += _settings_game.linkgraph.recalc_interval) {
    00191
    00192       /* don't calculate a link graph if the distribution is manual */
    00193       if (_settings_game.linkgraph.GetDistributionType(cargo) == DT_MANUAL) continue;
    00194
    00195       if (_date_fract == LinkGraph::COMPONENTS_SPAWN_TICK) {
    00196         _link_graphs[cargo].NextComponent();
    00197       } else /* LinkGraph::COMPONENTS_JOIN_TICK */ {
    00198         _link_graphs[cargo].Join();
    00199       }
    00200     }
    00201   }
    00202 }
    00203
    00212 NodeID LinkGraphComponent::AddNode(Station *st)
    00213 {
    00214   GoodsEntry &good = st->goods[this->cargo];
    00215   good.last_component = this->index;
    00216
    00217   bool do_resize = (this->nodes.size() == this->num_nodes);
    00218
    00219   if (do_resize) {
    00220     this->nodes.push_back(Node());
    00221     this->edges.push_back(std::vector<Edge>(this->num_nodes + 1));
    00222   }
    00223
    00224   this->nodes[this->num_nodes].Init(st->index, good.supply,
    00225       HasBit(good.acceptance_pickup, GoodsEntry::GES_ACCEPTANCE));
    00226
    00227   std::vector<Edge> &new_edges = this->edges[this->num_nodes];
    00228
    00229   /* reset the first edge starting at the new node */
    00230   new_edges[this->num_nodes].next_edge = INVALID_NODE;
    00231
    00232   for(NodeID i = 0; i < this->num_nodes; ++i) {
    00233     uint distance = DistanceManhattan(st->xy, Station::Get(this->nodes[i].station)->xy);
    00234     if (do_resize) this->edges[i].push_back(Edge());
    00235     new_edges[i].Init(distance);
    00236     this->edges[i][this->num_nodes].Init(distance);
    00237   }
    00238   return this->num_nodes++;
    00239 }
    00240
    00247 FORCEINLINE void LinkGraphComponent::AddEdge(NodeID from, NodeID to, uint capacity)
    00248 {
    00249   assert(from != to);
    00250   Edge &edge = this->edges[from][to];
    00251   Edge &first = this->edges[from][from];
    00252   edge.capacity = capacity;
    00253   edge.next_edge = first.next_edge;
    00254   first.next_edge = to;
    00255 }
    00256
    00266 void LinkGraphComponent::SetSize()
    00267 {
    00268   if (this->nodes.size() < this->num_nodes) {
    00269     for (EdgeMatrix::iterator i = this->edges.begin(); i != this->edges.end(); ++i) {
    00270       i->resize(this->num_nodes);
    00271     }
    00272     this->nodes.resize(this->num_nodes);
    00273     this->edges.resize(this->num_nodes, std::vector<Edge>(this->num_nodes));
    00274   }
    00275
    00276   for(uint i = 0; i < this->num_nodes; ++i) {
    00277     this->nodes[i].Init();
    00278     for (uint j = 0; j < this->num_nodes; ++j) {
    00279       this->edges[i][j].Init();
    00280     }
    00281   }
    00282 }
    00283
    00287 LinkGraphComponent::LinkGraphComponent() :
    00288     settings(_settings_game.linkgraph),
    00289     cargo(INVALID_CARGO),
    00290     num_nodes(0),
    00291     index(INVALID_LINKGRAPH_COMPONENT)
    00292 {}
    00293
    00297 void LinkGraphComponent::Init(LinkGraphComponentID id)
    00298 {
    00299   assert(this->num_nodes == 0);
    00300   this->index = id;
    00301   this->settings = _settings_game.linkgraph;
    00302 }
    00303
    00304
    00313 void Node::ExportNewFlows(FlowMap::iterator &it, FlowStatSet &dest, CargoID cargo)
    00314 {
    00315   StationID source = it->first;
    00316   FlowViaMap &source_flows = it->second;
    00317   if (!Station::IsValidID(source)) {
    00318     source_flows.clear();
    00319   } else {
    00320     Station *curr_station = Station::Get(this->station);
    00321     for (FlowViaMap::iterator update = source_flows.begin(); update != source_flows.end();) {
    00322       StationID next = update->first;
    00323       int planned = update->second;
    00324       assert(planned >= 0);
    00325
    00326       Station *via = Station::GetIfValid(next);
    00327       if (planned > 0 && via != NULL) {
    00328         uint distance = GetMovingAverageLength(curr_station, via);
    00329         if (next != this->station) {
    00330           const LinkStatMap &ls = curr_station->goods[cargo].link_stats;
    00331           if (ls.find(next) != ls.end()) {
    00332             dest.insert(FlowStat(distance, next, planned, 0));
    00333           }
    00334         } else {
    00335           dest.insert(FlowStat(distance, next, planned, 0));
    00336         }
    00337       }
    00338       source_flows.erase(update++);
    00339     }
    00340   }
    00341   assert(source_flows.empty());
    00342
    00343   this->flows.erase(it++);
    00344 }
    00345
    00350 void Node::ExportFlows(CargoID cargo) {
    00351   FlowStatMap &station_flows = Station::Get(this->station)->goods[cargo].flows;
    00352   FlowStatSet new_flows;
    00353   /* loop over all existing flows in the station and update them */
    00354   for(FlowStatMap::iterator station_outer_it(station_flows.begin()); station_outer_it != station_flows.end();) {
    00355     FlowMap::iterator node_outer_it(this->flows.find(station_outer_it->first));
    00356     if (node_outer_it == this->flows.end()) {
    00357       /* there are no flows for this source node anymore */
    00358       station_flows.erase(station_outer_it++);
    00359     } else {
    00360       FlowViaMap &source = node_outer_it->second;
    00361       FlowStatSet &dest = station_outer_it->second;
    00362       /* loop over the station's flow stats for this source node and update them */
    00363       for (FlowStatSet::iterator station_inner_it(dest.begin()); station_inner_it != dest.end();) {
    00364         FlowViaMap::iterator node_inner_it(source.find(station_inner_it->Via()));
    00365         if (node_inner_it != source.end()) {
    00366           assert(node_inner_it->second >= 0);
    00367           if (node_inner_it->second > 0) {
    00368             new_flows.insert(FlowStat(*station_inner_it, node_inner_it->second));
    00369           }
    00370           source.erase(node_inner_it);
    00371         }
    00372         dest.erase(station_inner_it++);
    00373       }
    00374       /* swap takes constant time, so we swap instead of adding all entries */
    00375       dest.swap(new_flows);
    00376       assert(new_flows.empty());
    00377       /* insert remaining flows for this source node */
    00378       ExportNewFlows(node_outer_it, dest, cargo);
    00379       /* careful: source_flows is dangling here */
    00380       ++station_outer_it;
    00381     }
    00382   }
    00383   /* loop over remaining flows (for other sources) in the node's map and insert them into the station */
    00384   for (FlowMap::iterator it(this->flows.begin()); it != this->flows.end();) {
    00385     ExportNewFlows(it, station_flows[it->first], cargo);
    00386   }
    00387   assert(this->flows.empty());
    00388 }
    00389
    00393 void LinkGraph::Join()
    00394 {
    00395   this->LinkGraphJob::Join();
    00396
    00397   for(NodeID node_id = 0; node_id < this->GetSize(); ++node_id) {
    00398     Node &node = this->GetNode(node_id);
    00399     if (Station::IsValidID(node.station)) {
    00400       node.ExportFlows(this->cargo);
    00401       Window *station_gui = FindWindowById(WC_STATION_VIEW, node.station);
    00402       if (station_gui != NULL) {
    00403         station_gui->OnInvalidateData(this->GetCargo());
    00404       }
    00405     }
    00406   }
    00407
    00408   this->LinkGraphComponent::Clear();
    00409 }
    00410
    00415 /* static */ void LinkGraphJob::RunLinkGraphJob(void *j)
    00416 {
    00417   LinkGraphJob *job = (LinkGraphJob *)j;
    00418   for (HandlerList::iterator i = _handlers.begin(); i != _handlers.end(); ++i) {
    00419     (*i)->Run(job);
    00420   }
    00421 }
    00422
    00426 /* static */ void LinkGraphJob::ClearHandlers()
    00427 {
    00428   for(HandlerList::iterator i = _handlers.begin(); i != _handlers.end(); ++i) {
    00429     delete (*i);
    00430   }
    00431   _handlers.clear();
    00432 }
    00433
    00441 void Path::Fork(Path *base, uint cap, int free_cap, uint dist)
    00442 {
    00443   this->capacity = min(base->capacity, cap);
    00444   this->free_capacity = min(base->free_capacity, free_cap);
    00445   this->distance = base->distance + dist;
    00446   assert(this->distance > 0);
    00447   if (this->parent != base) {
    00448     this->UnFork();
    00449     this->parent = base;
    00450     this->parent->num_children++;
    00451   }
    00452   this->origin = base->origin;
    00453 }
    00454
    00463 uint Path::AddFlow(uint new_flow, LinkGraphComponent *graph, bool only_positive)
    00464 {
    00465   if (this->parent != NULL) {
    00466     Edge &edge = graph->GetEdge(this->parent->node, this->node);
    00467     if (only_positive) {
    00468       uint usable_cap = edge.capacity * graph->GetSettings().short_path_saturation / 100;
    00469       if(usable_cap > edge.flow) {
    00470         new_flow = min(new_flow, usable_cap - edge.flow);
    00471       } else {
    00472         return 0;
    00473       }
    00474     }
    00475     new_flow = this->parent->AddFlow(new_flow, graph, only_positive);
    00476     if (new_flow > 0) {
    00477       graph->GetNode(parent->node).paths.insert(this);
    00478     }
    00479     edge.flow += new_flow;
    00480   }
    00481   this->flow += new_flow;
    00482   return new_flow;
    00483 }
    00484
    00490 Path::Path(NodeID n, bool source)  :
    00491   distance(source ? 0 : UINT_MAX),
    00492   capacity(0),
    00493   free_capacity(source ? INT_MAX : INT_MIN),
    00494   flow(0), node(n), origin(source ? n : INVALID_NODE),
    00495   num_children(0), parent(NULL)
    00496 {}
    00497
    00501 FORCEINLINE void LinkGraphJob::Join()
    00502 {
    00503   if (this->thread != NULL) {
    00504     this->thread->Join();
    00505     delete this->thread;
    00506     this->thread = NULL;
    00507   }
    00508 }
    00509
    00514 void LinkGraphJob::SpawnThread()
    00515 {
    00516   assert(this->thread == NULL);
    00517   if (!ThreadObject::New(&(LinkGraphJob::RunLinkGraphJob), this, &(this->thread))) {
    00518     this->thread = NULL;
    00519     /* Of course this will hang a bit.
    00520      * On the other hand, if you want to play games which make this hang noticably
    00521      * on a platform without threads then you'll probably get other problems first.
    00522      * OK:
    00523      * If someone comes and tells me that this hangs for him/her, I'll implement a
    00524      * smaller grained "Step" method for all handlers and add some more ticks where
    00525      * "Step" is called. No problem in principle.
    00526      */
    00527     LinkGraphJob::RunLinkGraphJob(this);
    00528   }
    00529 }
    00530
    00536 void LinkGraph::Init(CargoID cargo)
    00537 {
    00538   this->LinkGraphJob::Join();
    00539   this->LinkGraphComponent::Clear();
    00540
    00541   this->current_station_id = 0;
    00542   this->LinkGraphComponent::cargo = cargo;
    00543 }
    00544
    00548 void InitializeLinkGraphs()
    00549 {
    00550   for (CargoID c = 0; c < NUM_CARGO; ++c) _link_graphs[c].Init(c);
    00551
    00552   LinkGraphJob::ClearHandlers();
    00553   LinkGraphJob::AddHandler(new DemandHandler);
    00554   LinkGraphJob::AddHandler(new MCFHandler<MCF1stPass>);
    00555   LinkGraphJob::AddHandler(new FlowMapper);
    00556   LinkGraphJob::AddHandler(new MCFHandler<MCF2ndPass>);
    00557   LinkGraphJob::AddHandler(new FlowMapper);
    00558 }