# 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 "../stdafx.h"
    00013 #include "../map_func.h"
    00014 #include "../core/bitmath_func.hpp"
    00015 #include "../debug.h"
    00016 #include "../window_func.h"
    00017 #include "../window_gui.h"
    00018 #include "../moving_average.h"
    00019 #include "linkgraph.h"
    00020 #include "demands.h"
    00021 #include "mcf.h"
    00022 #include "flowmapper.h"
    00023 #include <queue>
    00024
    00028 LinkGraph _link_graphs[NUM_CARGO];
    00029
    00033 LinkGraphJob::HandlerList LinkGraphJob::_handlers;
    00034
    00041 inline void Node::Init(StationID st, uint sup, uint dem)
    00042 {
    00043   this->supply = sup;
    00044   this->undelivered_supply = sup;
    00045   this->demand = dem;
    00046   this->station = st;
    00047
    00048   for (PathSet::iterator i = this->paths.begin(); i != this->paths.end(); ++i) {
    00049     delete *i;
    00050   }
    00051   this->paths.clear();
    00052   this->flows.clear();
    00053 }
    00054
    00060 inline void Edge::Init(uint distance, uint capacity)
    00061 {
    00062   this->distance = distance;
    00063   this->capacity = capacity;
    00064   this->demand = 0;
    00065   this->unsatisfied_demand = 0;
    00066   this->flow = 0;
    00067   this->next_edge = INVALID_NODE;
    00068 }
    00069
    00070
    00077 void LinkGraph::CreateComponent(Station *first)
    00078 {
    00079   std::map<Station *, NodeID> index;
    00080   index[first] = this->AddNode(first);
    00081
    00082   std::queue<Station *> search_queue;
    00083   search_queue.push(first);
    00084
    00085   /* find all stations belonging to the current component */
    00086   while (!search_queue.empty()) {
    00087     Station *source = search_queue.front();
    00088     search_queue.pop();
    00089
    00090     const LinkStatMap &links = source->goods[this->cargo].link_stats;
    00091     for (LinkStatMap::const_iterator i = links.begin(); i != links.end(); ++i) {
    00092       Station *target = Station::GetIfValid(i->first);
    00093       if (target == NULL) continue;
    00094
    00095       std::map<Station *, NodeID>::iterator index_it = index.find(target);
    00096       if (index_it == index.end()) {
    00097         search_queue.push(target);
    00098         NodeID node = this->AddNode(target);
    00099         index[target] = node;
    00100
    00101         this->AddEdge(index[source], node, i->second.Capacity());
    00102       } else {
    00103         this->AddEdge(index[source], index_it->second, i->second.Capacity());
    00104       }
    00105     }
    00106   }
    00107
    00108   /* here the list of nodes and edges for this component is complete. */
    00109   this->SpawnThread();
    00110 }
    00111
    00125 void LinkGraph::NextComponent()
    00126 {
    00127   /* Check for no stations to avoid problems with Station::GetPoolSize()
    00128    * being 0 later and to avoid searching an empty pool.
    00129    */
    00130   if (Station::GetNumItems() == 0) return;
    00131
    00132   /* Don't mess with running jobs (might happen when changing interval).*/
    00133   if (this->GetSize() > 0) return;
    00134
    00135   /* The station pool may shrink when saving and subsequently loading a game as
    00136    * NULL entries at the end are cut off then. If the current station id points
    00137    * to one of those NULL entries we have to clamp it here to avoid an infinite
    00138    * loop later.
    00139    */
    00140   StationID last_station_id = min(this->current_station_id, Station::GetPoolSize() - 1);
    00141   LinkGraphComponentID current_component_id = this->LinkGraphComponent::index;
    00142
    00143   do {
    00144     if (++this->current_station_id >= Station::GetPoolSize()) {
    00145       /* Wrap around and recycle the component IDs. Use different
    00146        * divisibility by 2 than in the last run so that we can find out
    00147        * which stations haven't been seen in this run.
    00148        */
    00149       this->current_station_id = 0;
    00150       if (current_component_id % 2 == 0) {
    00151         current_component_id = 1;
    00152       } else {
    00153         current_component_id = 0;
    00154       }
    00155     }
    00156
    00157     /* find first station of next component */
    00158     Station *station = Station::GetIfValid(this->current_station_id);
    00159     if (station != NULL) {
    00160       GoodsEntry &ge = station->goods[this->cargo];
    00161       if (ge.last_component == INVALID_LINKGRAPH_COMPONENT ||
    00162           (ge.last_component + current_component_id) % 2 != 0) {
    00163         /* Different divisibility by 2: This station has not been seen
    00164          * in the current run over the link graph.
    00165          */
    00166
    00167         if (!ge.link_stats.empty()) {
    00168           this->LinkGraphComponent::Init(current_component_id + 2);
    00169           CreateComponent(station);
    00170           return;
    00171         }
    00172       }
    00173     }
    00174
    00175   } while (this->current_station_id != last_station_id);
    00176 }
    00177
    00183 void OnTick_LinkGraph()
    00184 {
    00185   if (_date_fract == LinkGraph::COMPONENTS_SPAWN_TICK ||
    00186       _date_fract == LinkGraph::COMPONENTS_JOIN_TICK) {
    00187
    00188     /* This creates a fair distribution of all link graphs' turns over
    00189      * the available dates.
    00190      */
    00191     for (uint cargo = _date % _settings_game.linkgraph.recalc_interval; cargo < NUM_CARGO;
    00192         cargo += _settings_game.linkgraph.recalc_interval) {
    00193
    00194       /* don't calculate a link graph if the distribution is manual */
    00195       if (_settings_game.linkgraph.GetDistributionType(cargo) == DT_MANUAL) continue;
    00196
    00197       if (_date_fract == LinkGraph::COMPONENTS_SPAWN_TICK) {
    00198         _link_graphs[cargo].NextComponent();
    00199       } else /* LinkGraph::COMPONENTS_JOIN_TICK */ {
    00200         _link_graphs[cargo].Join();
    00201       }
    00202     }
    00203   }
    00204 }
    00205
    00214 NodeID LinkGraphComponent::AddNode(Station *st)
    00215 {
    00216   GoodsEntry &good = st->goods[this->cargo];
    00217   good.last_component = this->index;
    00218
    00219   bool do_resize = (this->nodes.size() == this->num_nodes);
    00220
    00221   if (do_resize) {
    00222     this->nodes.push_back(Node());
    00223     this->edges.push_back(std::vector<Edge>(this->num_nodes + 1));
    00224   }
    00225
    00226   this->nodes[this->num_nodes].Init(st->index, good.supply,
    00227       HasBit(good.acceptance_pickup, GoodsEntry::GES_ACCEPTANCE));
    00228
    00229   std::vector<Edge> &new_edges = this->edges[this->num_nodes];
    00230
    00231   /* reset the first edge starting at the new node */
    00232   new_edges[this->num_nodes].next_edge = INVALID_NODE;
    00233
    00234   for (NodeID i = 0; i < this->num_nodes; ++i) {
    00235     uint distance = DistanceManhattan(st->xy, Station::Get(this->nodes[i].station)->xy);
    00236     if (do_resize) this->edges[i].push_back(Edge());
    00237     new_edges[i].Init(distance);
    00238     this->edges[i][this->num_nodes].Init(distance);
    00239   }
    00240   return this->num_nodes++;
    00241 }
    00242
    00249 inline void LinkGraphComponent::AddEdge(NodeID from, NodeID to, uint capacity)
    00250 {
    00251   assert(from != to);
    00252   Edge &edge = this->edges[from][to];
    00253   Edge &first = this->edges[from][from];
    00254   edge.capacity = capacity;
    00255   edge.next_edge = first.next_edge;
    00256   first.next_edge = to;
    00257 }
    00258
    00268 void LinkGraphComponent::SetSize()
    00269 {
    00270   if (this->nodes.size() < this->num_nodes) {
    00271     for (EdgeMatrix::iterator i = this->edges.begin(); i != this->edges.end(); ++i) {
    00272       i->resize(this->num_nodes);
    00273     }
    00274     this->nodes.resize(this->num_nodes);
    00275     this->edges.resize(this->num_nodes, std::vector<Edge>(this->num_nodes));
    00276   }
    00277
    00278   for (uint i = 0; i < this->num_nodes; ++i) {
    00279     this->nodes[i].Init();
    00280     for (uint j = 0; j < this->num_nodes; ++j) {
    00281       this->edges[i][j].Init();
    00282     }
    00283   }
    00284 }
    00285
    00289 LinkGraphComponent::LinkGraphComponent() :
    00290     settings(_settings_game.linkgraph),
    00291     cargo(INVALID_CARGO),
    00292     num_nodes(0),
    00293     index(INVALID_LINKGRAPH_COMPONENT)
    00294 {}
    00295
    00299 void LinkGraphComponent::Init(LinkGraphComponentID id)
    00300 {
    00301   assert(this->num_nodes == 0);
    00302   this->index = id;
    00303   this->settings = _settings_game.linkgraph;
    00304 }
    00305
    00306
    00315 void Node::ExportFlows(FlowMap::iterator &it, FlowStatMap &station_flows, CargoID cargo)
    00316 {
    00317   FlowStat *dest = NULL;
    00318   StationID source = it->first;
    00319   FlowViaMap &source_flows = it->second;
    00320   if (!Station::IsValidID(source)) {
    00321     source_flows.clear();
    00322   } else {
    00323     Station *curr_station = Station::Get(this->station);
    00324     for (FlowViaMap::iterator update = source_flows.begin(); update != source_flows.end();) {
    00325       StationID next = update->first;
    00326       int planned = update->second;
    00327       assert(planned >= 0);
    00328
    00329       Station *via = Station::GetIfValid(next);
    00330       if (planned > 0 && via != NULL) {
    00331         if (next == this->station ||
    00332             curr_station->goods[cargo].link_stats.find(next) !=
    00333             curr_station->goods[cargo].link_stats.end()) {
    00334           if (dest == NULL) {
    00335             dest = &(station_flows.insert(std::make_pair(it->first, FlowStat(next, planned))).first->second);
    00336           } else {
    00337             dest->AddShare(next, planned);
    00338           }
    00339         }
    00340       }
    00341       source_flows.erase(update++);
    00342     }
    00343   }
    00344
    00345   assert(source_flows.empty());
    00346
    00347   this->flows.erase(it++);
    00348 }
    00349
    00354 void Node::ExportFlows(CargoID cargo)
    00355 {
    00356   FlowStatMap &station_flows = Station::Get(this->station)->goods[cargo].flows;
    00357   station_flows.clear();
    00358
    00359   /* loop over flows in the node's map and insert them into the station */
    00360   for (FlowMap::iterator it(this->flows.begin()); it != this->flows.end();) {
    00361     this->ExportFlows(it, station_flows, cargo);
    00362   }
    00363   assert(this->flows.empty());
    00364 }
    00365
    00369 void LinkGraph::Join()
    00370 {
    00371   this->LinkGraphJob::Join();
    00372
    00373   for (NodeID node_id = 0; node_id < this->GetSize(); ++node_id) {
    00374     Node &node = this->GetNode(node_id);
    00375     if (Station::IsValidID(node.station)) {
    00376       node.ExportFlows(this->cargo);
    00377       InvalidateWindowData(WC_STATION_VIEW, node.station, this->GetCargo());
    00378     }
    00379   }
    00380
    00381   this->LinkGraphComponent::Clear();
    00382 }
    00383
    00388 /* static */ void LinkGraphJob::RunLinkGraphJob(void *j)
    00389 {
    00390   LinkGraphJob *job = (LinkGraphJob *)j;
    00391   for (HandlerList::iterator i = LinkGraphJob::_handlers.begin(); i != LinkGraphJob::_handlers.end(); ++i) {
    00392     (*i)->Run(job);
    00393   }
    00394 }
    00395
    00399 /* static */ void LinkGraphJob::ClearHandlers()
    00400 {
    00401   for (HandlerList::iterator i = LinkGraphJob::_handlers.begin(); i != LinkGraphJob::_handlers.end(); ++i) {
    00402     delete *i;
    00403   }
    00404   LinkGraphJob::_handlers.clear();
    00405 }
    00406
    00414 void Path::Fork(Path *base, uint cap, int free_cap, uint dist)
    00415 {
    00416   this->capacity = min(base->capacity, cap);
    00417   this->free_capacity = min(base->free_capacity, free_cap);
    00418   this->distance = base->distance + dist;
    00419   assert(this->distance > 0);
    00420   if (this->parent != base) {
    00421     this->Detach();
    00422     this->parent = base;
    00423     this->parent->num_children++;
    00424   }
    00425   this->origin = base->origin;
    00426 }
    00427
    00436 uint Path::AddFlow(uint new_flow, LinkGraphComponent *graph, bool only_positive)
    00437 {
    00438   if (this->parent != NULL) {
    00439     Edge &edge = graph->GetEdge(this->parent->node, this->node);
    00440     if (only_positive) {
    00441       uint usable_cap = edge.capacity * graph->GetSettings().short_path_saturation / 100;
    00442       if (usable_cap > edge.flow) {
    00443         new_flow = min(new_flow, usable_cap - edge.flow);
    00444       } else {
    00445         return 0;
    00446       }
    00447     }
    00448     new_flow = this->parent->AddFlow(new_flow, graph, only_positive);
    00449     if (new_flow > 0) {
    00450       graph->GetNode(this->parent->node).paths.insert(this);
    00451     }
    00452     edge.flow += new_flow;
    00453   }
    00454   this->flow += new_flow;
    00455   return new_flow;
    00456 }
    00457
    00463 Path::Path(NodeID n, bool source) :
    00464   distance(source ? 0 : UINT_MAX),
    00465   capacity(0),
    00466   free_capacity(source ? INT_MAX : INT_MIN),
    00467   flow(0), node(n), origin(source ? n : INVALID_NODE),
    00468   num_children(0), parent(NULL)
    00469 {}
    00470
    00474 inline void LinkGraphJob::Join()
    00475 {
    00476   if (this->thread == NULL) return;
    00477   this->thread->Join();
    00478   delete this->thread;
    00479   this->thread = NULL;
    00480 }
    00481
    00486 void LinkGraphJob::SpawnThread()
    00487 {
    00488   assert(this->thread == NULL);
    00489   if (!ThreadObject::New(&(LinkGraphJob::RunLinkGraphJob), this, &(this->thread))) {
    00490     this->thread = NULL;
    00491     /* Of course this will hang a bit.
    00492      * On the other hand, if you want to play games which make this hang noticably
    00493      * on a platform without threads then you'll probably get other problems first.
    00494      * OK:
    00495      * If someone comes and tells me that this hangs for him/her, I'll implement a
    00496      * smaller grained "Step" method for all handlers and add some more ticks where
    00497      * "Step" is called. No problem in principle.
    00498      */
    00499     LinkGraphJob::RunLinkGraphJob(this);
    00500   }
    00501 }
    00502
    00508 void LinkGraph::Init(CargoID cargo)
    00509 {
    00510   this->LinkGraphJob::Join();
    00511   this->LinkGraphComponent::Clear();
    00512
    00513   this->current_station_id = 0;
    00514   this->LinkGraphComponent::cargo = cargo;
    00515 }
    00516
    00520 void InitializeLinkGraphs()
    00521 {
    00522   for (CargoID c = 0; c < NUM_CARGO; ++c) _link_graphs[c].Init(c);
    00523
    00524   LinkGraphJob::ClearHandlers();
    00525   LinkGraphJob::AddHandler(new DemandHandler);
    00526   LinkGraphJob::AddHandler(new MCFHandler<MCF1stPass>);
    00527   LinkGraphJob::AddHandler(new FlowMapper);
    00528   LinkGraphJob::AddHandler(new MCFHandler<MCF2ndPass>);
    00529   LinkGraphJob::AddHandler(new FlowMapper);
    00530 }