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 "../core/bitmath_func.hpp"
00014 #include "../core/pool_func.hpp"
00015 #include "../core/random_func.hpp"
00016 #include "../map_func.h"
00017 #include "../debug.h"
00018 #include "../window_func.h"
00019 #include "../window_gui.h"
00020 #include "linkgraph.h"
00021 #include "init.h"
00022 #include "demands.h"
00023 #include "mcf.h"
00024 #include "flowmapper.h"
00025 
00026 /* Initialize the link-graph-pool */
00027 LinkGraphPool _link_graph_pool("LinkGraph");
00028 INSTANTIATE_POOL_METHODS(LinkGraph)
00029 
00030 /* Initialize the link-graph-job-pool */
00031 LinkGraphJobPool _link_graph_job_pool("LinkGraphJob");
00032 INSTANTIATE_POOL_METHODS(LinkGraphJob)
00033 
00034 
00040 inline void Node::Init(StationID st, uint demand)
00041 {
00042   this->supply = 0;
00043   this->demand = demand;
00044   this->station = st;
00045   this->last_update = INVALID_DATE;
00046 }
00047 
00052 inline void Edge::Init(uint distance)
00053 {
00054   this->distance = distance;
00055   this->capacity = 0;
00056   this->usage = 0;
00057   this->last_update = INVALID_DATE;
00058   this->next_edge = INVALID_NODE;
00059 }
00060 
00061 void LinkGraph::Compress()
00062 {
00063   this->last_compression = (_date + this->last_compression) / 2;
00064   for (NodeID node1 = 0; node1 < this->num_nodes; ++node1) {
00065     this->nodes[node1].supply /= 2;
00066     for (NodeID node2 = 0; node2 < this->num_nodes; ++node2) {
00067       this->edges[node1][node2].capacity /= 2;
00068       this->edges[node1][node2].usage /= 2;
00069     }
00070   }
00071 }
00072 
00077 void LinkGraph::Merge(LinkGraph *other)
00078 {
00079   Date age = _date - this->last_compression + 1;
00080   Date other_age = _date - other->last_compression + 1;
00081   NodeID first = this->num_nodes;
00082   for (NodeID node1 = 0; node1 < other->num_nodes; ++node1) {
00083     Station *st = Station::Get(other->nodes[node1].station);
00084     NodeID new_node = this->AddNode(st);
00085     this->nodes[new_node].supply = other->nodes[node1].supply * age / other_age;
00086     st->goods[this->cargo].link_graph = this->index;
00087     st->goods[this->cargo].node = new_node;
00088     for (NodeID node2 = 0; node2 < node1; ++node2) {
00089       Edge &forward = this->edges[new_node][first + node2];
00090       Edge &backward = this->edges[first + node2][new_node];
00091       forward = other->edges[node1][node2];
00092       backward = other->edges[node2][node1];
00093       forward.capacity = forward.capacity * age / other_age;
00094       forward.usage = forward.usage * age / other_age;
00095       if (forward.next_edge != INVALID_NODE) forward.next_edge += first;
00096       backward.capacity = backward.capacity * age / other_age;
00097       backward.usage = backward.usage * age / other_age;
00098       if (backward.next_edge != INVALID_NODE) backward.next_edge += first;
00099     }
00100     Edge &new_start = this->edges[new_node][new_node];
00101     new_start = other->edges[node1][node1];
00102     if (new_start.next_edge != INVALID_NODE) new_start.next_edge += first;
00103   }
00104   delete other;
00105 }
00106 
00111 void LinkGraph::RemoveNode(NodeID id)
00112 {
00113   assert(id < this->num_nodes);
00114 
00115   for (NodeID i = 0; i <= this->num_nodes; ++i) {
00116     this->RemoveEdge(i, id);
00117     NodeID prev = i;
00118     NodeID next = this->GetFirstEdge(i);
00119     while (next != INVALID_NODE) {
00120       if (next == this->num_nodes - 1) {
00121         this->edges[i][prev].next_edge = id;
00122         break;
00123       }
00124     }
00125     this->edges[i][id] = this->edges[i][this->num_nodes - 1];
00126   }
00127   --this->num_nodes;
00128   this->nodes.Erase(this->nodes.Get(id));
00129   this->edges.EraseColumn(id);
00130   /* Not doing EraseRow here, as having the extra invalid row doesn't hurt
00131    * and removing it would trigger a lot of memmove. The data has already
00132    * been copied around in the loop above. */
00133 }
00134 
00143 NodeID LinkGraph::AddNode(const Station *st)
00144 {
00145   const GoodsEntry &good = st->goods[this->cargo];
00146 
00147   if (this->nodes.Length() == this->num_nodes) {
00148     this->nodes.Append();
00149     /* Avoid reducing the height of the matrix as that is expensive and we
00150      * most likely will increase it again later which is again expensive. */
00151     this->edges.Resize(this->num_nodes + 1,
00152         max(uint(this->num_nodes + 1), this->edges.Height()));
00153   }
00154 
00155   this->nodes[this->num_nodes].Init(st->index,
00156       HasBit(good.acceptance_pickup, GoodsEntry::GES_ACCEPTANCE));
00157 
00158   Edge *new_edges = this->edges[this->num_nodes];
00159 
00160   /* Reset the first edge starting at the new node */
00161   new_edges[this->num_nodes].next_edge = INVALID_NODE;
00162 
00163   for (NodeID i = 0; i <= this->num_nodes; ++i) {
00164     uint distance = DistanceManhattan(st->xy, Station::Get(this->nodes[i].station)->xy);
00165     new_edges[i].Init(distance);
00166     this->edges[i][this->num_nodes].Init(distance);
00167   }
00168   return this->num_nodes++;
00169 }
00170 
00177 inline void LinkGraph::AddEdge(NodeID from, NodeID to, uint capacity)
00178 {
00179   assert(from != to && from < this->num_nodes && to < this->num_nodes);
00180   Edge &edge = this->edges[from][to];
00181   Edge &first = this->edges[from][from];
00182   edge.capacity = capacity;
00183   edge.next_edge = first.next_edge;
00184   first.next_edge = to;
00185   edge.last_update = _date;
00186 }
00187 
00188 void LinkGraph::RemoveEdge(NodeID from, NodeID to)
00189 {
00190   if (from == to) return;
00191   Edge &edge = this->edges[from][to];
00192   edge.capacity = 0;
00193   edge.last_update = INVALID_DATE;
00194   edge.usage = 0;
00195 
00196   NodeID prev = from;
00197   NodeID next = this->GetFirstEdge(from);
00198   while (next != INVALID_NODE) {
00199     if (next == to) {
00200       /* Will be removed, skip it. */
00201       next = this->edges[from][prev].next_edge = edge.next_edge;
00202       break;
00203     } else {
00204       prev = next;
00205       next = this->edges[from][next].next_edge;
00206     }
00207   }
00208 }
00209 
00218 void LinkGraph::UpdateEdge(NodeID from, NodeID to, uint capacity, uint usage)
00219 {
00220   Edge &edge = this->edges[from][to];
00221   if (edge.capacity == 0) {
00222     this->AddEdge(from, to, capacity);
00223     if (usage != UINT_MAX) edge.usage += usage;
00224   } else {
00225     if (usage == UINT_MAX) {
00226       edge.capacity = max(edge.capacity, capacity);
00227     } else {
00228       assert(capacity >= usage);
00229       edge.capacity += capacity;
00230       edge.usage += usage;
00231     }
00232     edge.last_update = _date;
00233   }
00234 }
00235 
00245 void LinkGraph::SetSize()
00246 {
00247   if (this->nodes.Length() < this->num_nodes) {
00248     this->edges.Resize(this->num_nodes, this->num_nodes);
00249     this->nodes.Resize(this->num_nodes);
00250   }
00251 
00252   for (uint i = 0; i < this->num_nodes; ++i) {
00253     this->nodes[i].Init();
00254     Edge *column = this->edges[i];
00255     for (uint j = 0; j < this->num_nodes; ++j) {
00256       column[j].Init();
00257     }
00258   }
00259 }
00260 
00267 LinkGraphJob::LinkGraphJob(const LinkGraph &orig) :
00268     /* Copying the link graph here also copies its index member.
00269      * This is on purpose. */
00270     link_graph(orig),
00271     settings(_settings_game.linkgraph),
00272     thread(NULL),
00273     join_date(_date + _settings_game.linkgraph.recalc_time)
00274 {
00275 }
00276 
00280 LinkGraphJob::~LinkGraphJob()
00281 {
00282   assert(this->thread == NULL);
00283   uint size = this->link_graph.GetSize();
00284   for (NodeID node_id = 0; node_id < size; ++node_id) {
00285     StationID &station = this->link_graph.GetNode(node_id).station;
00286     if (!Station::IsValidID(station)) {
00287       /* Station got removed during the link graph run. We have to remove all
00288        * flows pointing to it now. This is costly but it should be rare. */
00289       for (NodeID from_id = 0; from_id < size; ++from_id) {
00290         if (this->link_graph.GetEdge(from_id, node_id).capacity > 0) {
00291           FlowStatMap &flows = this->nodes[from_id].flows;
00292           for (FlowStatMap::iterator it(flows.begin()); it != flows.end(); ++it) {
00293             it->second.ChangeShare(station, INT_MIN);
00294           }
00295         }
00296       }
00297       station = INVALID_STATION;
00298     }
00299   }
00300   for (NodeID node_id = 0; node_id < size; ++node_id) {
00301     StationID station = this->link_graph.GetNode(node_id).station;
00302     if (station != INVALID_STATION) {
00303       InvalidateWindowData(WC_STATION_VIEW, station, this->link_graph.GetCargo());
00304       Station::Get(station)->goods[this->link_graph.GetCargo()].flows.
00305           swap(this->GetNode(node_id).flows);
00306     }
00307   }
00308 }
00309 
00313 void LinkGraphSchedule::SpawnNext()
00314 {
00315   if (this->schedule.empty()) return;
00316   LinkGraph *next = this->schedule.front();
00317   assert(next == LinkGraph::Get(next->index));
00318   this->schedule.pop_front();
00319   if (LinkGraphJob::CanAllocateItem()) {
00320     LinkGraphJob *job = new LinkGraphJob(*next);
00321     job->SpawnThread();
00322     this->running.push_back(job);
00323   } else {
00324     DEBUG(misc, 0, "Can't allocate link graph job");
00325   }
00326 }
00327 
00331 void LinkGraphSchedule::JoinNext()
00332 {
00333   if (this->running.empty()) return;
00334   LinkGraphJob *next = this->running.front();
00335   if (!next->IsFinished()) return;
00336   this->running.pop_front();
00337   LinkGraphID id = next->Graph().index;
00338   next->JoinThread();
00339   delete next;
00340   if (LinkGraph::IsValidID(id)) {
00341     LinkGraph *lg = LinkGraph::Get(id);
00342     this->Unqueue(lg); // Unqueue to avoid double-queueing recycled IDs.
00343     this->Queue(lg);
00344   }
00345 }
00346 
00351 /* static */ void LinkGraphSchedule::Run(void *j)
00352 {
00353   LinkGraphJob *job = (LinkGraphJob *)j;
00354   LinkGraphSchedule *schedule = LinkGraphSchedule::Instance();
00355   for (uint i = 0; i < lengthof(schedule->handlers); ++i) {
00356     schedule->handlers[i]->Run(job);
00357   }
00358 }
00359 
00363 void LinkGraphJob::JoinThread()
00364 {
00365   if (this->thread != NULL) {
00366     this->thread->Join();
00367     delete this->thread;
00368     this->thread = NULL;
00369   }
00370 }
00371 
00376 void LinkGraphJob::SpawnThread()
00377 {
00378   assert(this->thread == NULL);
00379   if (!ThreadObject::New(&(LinkGraphSchedule::Run), this, &(this->thread))) {
00380     this->thread = NULL;
00381     /* Of course this will hang a bit.
00382      * On the other hand, if you want to play games which make this hang noticably
00383      * on a platform without threads then you'll probably get other problems first.
00384      * OK:
00385      * If someone comes and tells me that this hangs for him/her, I'll implement a
00386      * smaller grained "Step" method for all handlers and add some more ticks where
00387      * "Step" is called. No problem in principle.
00388      */
00389     LinkGraphSchedule::Run(this);
00390   }
00391 }
00392 
00397 void LinkGraphSchedule::SpawnAll()
00398 {
00399   for (JobList::iterator i = this->running.begin(); i != this->running.end(); ++i) {
00400     (*i)->SpawnThread();
00401   }
00402 }
00403 
00407 /* static */ void LinkGraphSchedule::Clear()
00408 {
00409   LinkGraphSchedule *inst = LinkGraphSchedule::Instance();
00410   for (JobList::iterator i(inst->running.begin()); i != inst->running.end(); ++i) {
00411     (*i)->JoinThread();
00412   }
00413   inst->running.clear();
00414   inst->schedule.clear();
00415 }
00416 
00420 LinkGraphSchedule::LinkGraphSchedule()
00421 {
00422   this->handlers[0] = new InitHandler;
00423   this->handlers[1] = new DemandHandler;
00424   this->handlers[2] = new MCFHandler<MCF1stPass>;
00425   this->handlers[3] = new FlowMapper;
00426   this->handlers[4] = new MCFHandler<MCF2ndPass>;
00427   this->handlers[5] = new FlowMapper;
00428 }
00429 
00433 LinkGraphSchedule::~LinkGraphSchedule()
00434 {
00435   this->Clear();
00436   for (uint i = 0; i < lengthof(this->handlers); ++i) {
00437     delete this->handlers[i];
00438   }
00439 }
00440 
00444 /* static */ LinkGraphSchedule *LinkGraphSchedule::Instance()
00445 {
00446   static LinkGraphSchedule inst;
00447   return &inst;
00448 }
00449 
00453 void OnTick_LinkGraph()
00454 {
00455   if (_date_fract == LinkGraphSchedule::SPAWN_JOIN_TICK) {
00456     Date offset = _date % _settings_game.linkgraph.recalc_interval;
00457     if (offset == 0) {
00458       LinkGraphSchedule::Instance()->SpawnNext();
00459     } else if (offset == _settings_game.linkgraph.recalc_interval / 2) {
00460       LinkGraphSchedule::Instance()->JoinNext();
00461     }
00462   } else if (_date_fract == LinkGraph::COMPRESSION_TICK) {
00463     LinkGraph *lg;
00464     /* Compress graphs after 256 to 512 days; approximately once a year. */
00465     int cutoff = RandomRange(256) + 256;
00466     FOR_ALL_LINK_GRAPHS(lg) {
00467       if (_date - lg->GetLastCompression() > cutoff) {
00468         lg->Compress();
00469         break;
00470       }
00471     }
00472   }
00473 }
00474 
00483 void Path::Fork(Path *base, uint cap, int free_cap, uint dist)
00484 {
00485   this->capacity = min(base->capacity, cap);
00486   this->free_capacity = min(base->free_capacity, free_cap);
00487   this->distance = base->distance + dist;
00488   assert(this->distance > 0);
00489   if (this->parent != base) {
00490     this->Detach();
00491     this->parent = base;
00492     this->parent->num_children++;
00493   }
00494   this->origin = base->origin;
00495 }
00496 
00505 uint Path::AddFlow(uint new_flow, LinkGraphJob *job, uint max_saturation)
00506 {
00507   if (this->parent != NULL) {
00508     EdgeAnnotation &edge = job->GetEdge(this->parent->node, this->node);
00509     if (max_saturation != UINT_MAX) {
00510       uint usable_cap = job->Graph().GetEdge(this->parent->node, this->node).capacity *
00511           max_saturation / 100;
00512       if (usable_cap > edge.flow) {
00513         new_flow = min(new_flow, usable_cap - edge.flow);
00514       } else {
00515         return 0;
00516       }
00517     }
00518     new_flow = this->parent->AddFlow(new_flow, job, max_saturation);
00519     if (new_flow > 0) {
00520       job->GetNode(this->parent->node).paths.insert(this);
00521     }
00522     edge.flow += new_flow;
00523   }
00524   this->flow += new_flow;
00525   return new_flow;
00526 }
00527 
00533 Path::Path(NodeID n, bool source) :
00534   distance(source ? 0 : UINT_MAX),
00535   capacity(0),
00536   free_capacity(source ? INT_MAX : INT_MIN),
00537   flow(0), node(n), origin(source ? n : INVALID_NODE),
00538   num_children(0), parent(NULL)
00539 {}
00540