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