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 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 FORCEINLINE 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   if (this->GetSize() > 0) return; // don't mess with running jobs (might happen when changing interval)
00128   StationID last_station_id = this->current_station_id;
00129   LinkGraphComponentID current_component_id = this->LinkGraphComponent::index;
00130 
00131   do {
00132     if (++this->current_station_id >= Station::GetPoolSize()) {
00133       /* Wrap around and recycle the component IDs. Use different
00134        * divisibility by 2 than in the last run so that we can find out
00135        * which stations haven't been seen in this run.
00136        */
00137       this->current_station_id = 0;
00138       if (current_component_id % 2 == 0) {
00139         current_component_id = 1;
00140       } else {
00141         current_component_id = 0;
00142       }
00143     }
00144 
00145     /* find first station of next component */
00146     Station *station = Station::GetIfValid(this->current_station_id);
00147     if (station != NULL) {
00148       GoodsEntry &ge = station->goods[this->cargo];
00149       if (ge.last_component == INVALID_LINKGRAPH_COMPONENT ||
00150           (ge.last_component + current_component_id) % 2 != 0) {
00151         /* Different divisibility by 2: This station has not been seen
00152          * in the current run over the link graph.
00153          */
00154 
00155         if (!ge.link_stats.empty()) {
00156           this->LinkGraphComponent::Init(current_component_id + 2);
00157           CreateComponent(station);
00158           return;
00159         }
00160       }
00161     }
00162 
00163   } while (this->current_station_id != last_station_id);
00164 }
00165 
00171 void OnTick_LinkGraph()
00172 {
00173   if (_date_fract == LinkGraph::COMPONENTS_SPAWN_TICK ||
00174       _date_fract == LinkGraph::COMPONENTS_JOIN_TICK) {
00175 
00176     /* This creates a fair distribution of all link graphs' turns over
00177      * the available dates.
00178      */
00179     for (uint cargo = _date % _settings_game.linkgraph.recalc_interval; cargo < NUM_CARGO;
00180         cargo += _settings_game.linkgraph.recalc_interval) {
00181 
00182       /* don't calculate a link graph if the distribution is manual */
00183       if (_settings_game.linkgraph.GetDistributionType(cargo) == DT_MANUAL) continue;
00184 
00185       if (_date_fract == LinkGraph::COMPONENTS_SPAWN_TICK) {
00186         _link_graphs[cargo].NextComponent();
00187       } else /* LinkGraph::COMPONENTS_JOIN_TICK */ {
00188         _link_graphs[cargo].Join();
00189       }
00190     }
00191   }
00192 }
00193 
00202 NodeID LinkGraphComponent::AddNode(Station *st)
00203 {
00204   GoodsEntry &good = st->goods[this->cargo];
00205   good.last_component = this->index;
00206 
00207   bool do_resize = (this->nodes.size() == this->num_nodes);
00208 
00209   if (do_resize) {
00210     this->nodes.push_back(Node());
00211     this->edges.push_back(std::vector<Edge>(this->num_nodes + 1));
00212   }
00213 
00214   this->nodes[this->num_nodes].Init(st->index, good.supply,
00215       HasBit(good.acceptance_pickup, GoodsEntry::ACCEPTANCE));
00216 
00217   std::vector<Edge> &new_edges = this->edges[this->num_nodes];
00218 
00219   /* reset the first edge starting at the new node */
00220   new_edges[this->num_nodes].next_edge = INVALID_NODE;
00221 
00222   for (NodeID i = 0; i < this->num_nodes; ++i) {
00223     uint distance = DistanceManhattan(st->xy, Station::Get(this->nodes[i].station)->xy);
00224     if (do_resize) this->edges[i].push_back(Edge());
00225     new_edges[i].Init(distance);
00226     this->edges[i][this->num_nodes].Init(distance);
00227   }
00228   return this->num_nodes++;
00229 }
00230 
00237 FORCEINLINE void LinkGraphComponent::AddEdge(NodeID from, NodeID to, uint capacity)
00238 {
00239   assert(from != to);
00240   Edge &edge = this->edges[from][to];
00241   Edge &first = this->edges[from][from];
00242   edge.capacity = capacity;
00243   edge.next_edge = first.next_edge;
00244   first.next_edge = to;
00245 }
00246 
00256 void LinkGraphComponent::SetSize()
00257 {
00258   if (this->nodes.size() < this->num_nodes) {
00259     for (EdgeMatrix::iterator i = this->edges.begin(); i != this->edges.end(); ++i) {
00260       i->resize(this->num_nodes);
00261     }
00262     this->nodes.resize(this->num_nodes);
00263     this->edges.resize(this->num_nodes, std::vector<Edge>(this->num_nodes));
00264   }
00265 
00266   for (uint i = 0; i < this->num_nodes; ++i) {
00267     this->nodes[i].Init();
00268     for (uint j = 0; j < this->num_nodes; ++j) {
00269       this->edges[i][j].Init();
00270     }
00271   }
00272 }
00273 
00277 LinkGraphComponent::LinkGraphComponent() :
00278     settings(_settings_game.linkgraph),
00279     cargo(INVALID_CARGO),
00280     num_nodes(0),
00281     index(INVALID_LINKGRAPH_COMPONENT)
00282 {}
00283 
00287 void LinkGraphComponent::Init(LinkGraphComponentID id)
00288 {
00289   assert(this->num_nodes == 0);
00290   this->index = id;
00291   this->settings = _settings_game.linkgraph;
00292 }
00293 
00294 
00303 void Node::ExportNewFlows(FlowMap::iterator &it, FlowStatSet &dest, CargoID cargo)
00304 {
00305   StationID source = it->first;
00306   FlowViaMap &source_flows = it->second;
00307   if (!Station::IsValidID(source)) {
00308     source_flows.clear();
00309   } else {
00310     Station *curr_station = Station::Get(this->station);
00311     for (FlowViaMap::iterator update = source_flows.begin(); update != source_flows.end();) {
00312       StationID next = update->first;
00313       int planned = update->second;
00314       assert(planned >= 0);
00315 
00316       Station *via = Station::GetIfValid(next);
00317       if (planned > 0 && via != NULL) {
00318         uint distance = GetMovingAverageLength(curr_station, via);
00319         if (next != this->station) {
00320           const LinkStatMap &ls = curr_station->goods[cargo].link_stats;
00321           if (ls.find(next) != ls.end()) {
00322             dest.insert(FlowStat(distance, next, planned, 0));
00323           }
00324         } else {
00325           dest.insert(FlowStat(distance, next, planned, 0));
00326         }
00327       }
00328       source_flows.erase(update++);
00329     }
00330   }
00331   assert(source_flows.empty());
00332 
00333   this->flows.erase(it++);
00334 }
00335 
00340 void Node::ExportFlows(CargoID cargo)
00341 {
00342   FlowStatMap &station_flows = Station::Get(this->station)->goods[cargo].flows;
00343   FlowStatSet new_flows;
00344   /* loop over all existing flows in the station and update them */
00345   for (FlowStatMap::iterator station_outer_it(station_flows.begin()); station_outer_it != station_flows.end();) {
00346     FlowMap::iterator node_outer_it(this->flows.find(station_outer_it->first));
00347     if (node_outer_it == this->flows.end()) {
00348       /* there are no flows for this source node anymore */
00349       station_flows.erase(station_outer_it++);
00350     } else {
00351       FlowViaMap &source = node_outer_it->second;
00352       FlowStatSet &dest = station_outer_it->second;
00353       /* loop over the station's flow stats for this source node and update them */
00354       for (FlowStatSet::iterator station_inner_it(dest.begin()); station_inner_it != dest.end();) {
00355         FlowViaMap::iterator node_inner_it(source.find(station_inner_it->Via()));
00356         if (node_inner_it != source.end()) {
00357           assert(node_inner_it->second >= 0);
00358           if (node_inner_it->second > 0) {
00359             new_flows.insert(FlowStat(*station_inner_it, node_inner_it->second));
00360           }
00361           source.erase(node_inner_it);
00362         }
00363         dest.erase(station_inner_it++);
00364       }
00365       /* swap takes constant time, so we swap instead of adding all entries */
00366       dest.swap(new_flows);
00367       assert(new_flows.empty());
00368       /* insert remaining flows for this source node */
00369       ExportNewFlows(node_outer_it, dest, cargo);
00370       /* careful: source_flows is dangling here */
00371       ++station_outer_it;
00372     }
00373   }
00374   /* loop over remaining flows (for other sources) in the node's map and insert them into the station */
00375   for (FlowMap::iterator it(this->flows.begin()); it != this->flows.end();) {
00376     ExportNewFlows(it, station_flows[it->first], cargo);
00377   }
00378   assert(this->flows.empty());
00379 }
00380 
00384 void LinkGraph::Join()
00385 {
00386   this->LinkGraphJob::Join();
00387 
00388   for (NodeID node_id = 0; node_id < this->GetSize(); ++node_id) {
00389     Node &node = this->GetNode(node_id);
00390     if (Station::IsValidID(node.station)) {
00391       node.ExportFlows(this->cargo);
00392       InvalidateWindowData(WC_STATION_VIEW, node.station, this->GetCargo());
00393     }
00394   }
00395 
00396   this->LinkGraphComponent::Clear();
00397 }
00398 
00403 /* static */ void LinkGraphJob::RunLinkGraphJob(void *j)
00404 {
00405   LinkGraphJob *job = (LinkGraphJob *)j;
00406   for (HandlerList::iterator i = _handlers.begin(); i != _handlers.end(); ++i) {
00407     (*i)->Run(job);
00408   }
00409 }
00410 
00414 /* static */ void LinkGraphJob::ClearHandlers()
00415 {
00416   for (HandlerList::iterator i = _handlers.begin(); i != _handlers.end(); ++i) {
00417     delete *i;
00418   }
00419   _handlers.clear();
00420 }
00421 
00429 void Path::Fork(Path *base, uint cap, int free_cap, uint dist)
00430 {
00431   this->capacity = min(base->capacity, cap);
00432   this->free_capacity = min(base->free_capacity, free_cap);
00433   this->distance = base->distance + dist;
00434   assert(this->distance > 0);
00435   if (this->parent != base) {
00436     this->Detach();
00437     this->parent = base;
00438     this->parent->num_children++;
00439   }
00440   this->origin = base->origin;
00441 }
00442 
00451 uint Path::AddFlow(uint new_flow, LinkGraphComponent *graph, bool only_positive)
00452 {
00453   if (this->parent != NULL) {
00454     Edge &edge = graph->GetEdge(this->parent->node, this->node);
00455     if (only_positive) {
00456       uint usable_cap = edge.capacity * graph->GetSettings().short_path_saturation / 100;
00457       if (usable_cap > edge.flow) {
00458         new_flow = min(new_flow, usable_cap - edge.flow);
00459       } else {
00460         return 0;
00461       }
00462     }
00463     new_flow = this->parent->AddFlow(new_flow, graph, only_positive);
00464     if (new_flow > 0) {
00465       graph->GetNode(this->parent->node).paths.insert(this);
00466     }
00467     edge.flow += new_flow;
00468   }
00469   this->flow += new_flow;
00470   return new_flow;
00471 }
00472 
00478 Path::Path(NodeID n, bool source) :
00479   distance(source ? 0 : UINT_MAX),
00480   capacity(0),
00481   free_capacity(source ? INT_MAX : INT_MIN),
00482   flow(0), node(n), origin(source ? n : INVALID_NODE),
00483   num_children(0), parent(NULL)
00484 {}
00485 
00489 FORCEINLINE void LinkGraphJob::Join()
00490 {
00491   if (this->thread == NULL) return;
00492   this->thread->Join();
00493   delete this->thread;
00494   this->thread = NULL;
00495 }
00496 
00501 void LinkGraphJob::SpawnThread()
00502 {
00503   assert(this->thread == NULL);
00504   if (!ThreadObject::New(&(LinkGraphJob::RunLinkGraphJob), this, &(this->thread))) {
00505     this->thread = NULL;
00506     /* Of course this will hang a bit.
00507      * On the other hand, if you want to play games which make this hang noticably
00508      * on a platform without threads then you'll probably get other problems first.
00509      * OK:
00510      * If someone comes and tells me that this hangs for him/her, I'll implement a
00511      * smaller grained "Step" method for all handlers and add some more ticks where
00512      * "Step" is called. No problem in principle.
00513      */
00514     LinkGraphJob::RunLinkGraphJob(this);
00515   }
00516 }
00517 
00523 void LinkGraph::Init(CargoID cargo)
00524 {
00525   this->LinkGraphJob::Join();
00526   this->LinkGraphComponent::Clear();
00527 
00528   this->current_station_id = 0;
00529   this->LinkGraphComponent::cargo = cargo;
00530 }
00531 
00535 void InitializeLinkGraphs()
00536 {
00537   for (CargoID c = 0; c < NUM_CARGO; ++c) _link_graphs[c].Init(c);
00538 
00539   LinkGraphJob::ClearHandlers();
00540   LinkGraphJob::AddHandler(new DemandHandler);
00541   LinkGraphJob::AddHandler(new MCFHandler<MCF1stPass>);
00542   LinkGraphJob::AddHandler(new FlowMapper);
00543   LinkGraphJob::AddHandler(new MCFHandler<MCF2ndPass>);
00544   LinkGraphJob::AddHandler(new FlowMapper);
00545 }

Generated on Sun Jun 5 04:19:57 2011 for OpenTTD by  doxygen 1.6.1