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 }