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   --this->num_nodes;
00116   for (NodeID i = 0; i <= this->num_nodes; ++i) {
00117     this->RemoveEdge(i, id);
00118     NodeID prev = i;
00119     NodeID next = this->GetFirstEdge(i);
00120     while (next != INVALID_NODE) {
00121       if (next == this->num_nodes) {
00122         this->edges[i][prev].next_edge = id;
00123         break;
00124       }
00125       prev = next;
00126       next = this->edges[i][prev].next_edge;
00127     }
00128     this->edges[i][id] = this->edges[i][this->num_nodes];
00129   }
00130   Station::Get(this->nodes[this->num_nodes].station)->goods[this->cargo].node = id;
00131   this->nodes.Erase(this->nodes.Get(id));
00132   this->edges.EraseColumn(id);
00133   /* Not doing EraseRow here, as having the extra invalid row doesn't hurt
00134    * and removing it would trigger a lot of memmove. The data has already
00135    * been copied around in the loop above. */
00136 }
00137 
00146 NodeID LinkGraph::AddNode(const Station *st)
00147 {
00148   const GoodsEntry &good = st->goods[this->cargo];
00149 
00150   if (this->nodes.Length() == this->num_nodes) {
00151     this->nodes.Append();
00152     /* Avoid reducing the height of the matrix as that is expensive and we
00153      * most likely will increase it again later which is again expensive. */
00154     this->edges.Resize(this->num_nodes + 1,
00155         max(uint(this->num_nodes + 1), this->edges.Height()));
00156   }
00157 
00158   this->nodes[this->num_nodes].Init(st->index,
00159       HasBit(good.acceptance_pickup, GoodsEntry::GES_ACCEPTANCE));
00160 
00161   Edge *new_edges = this->edges[this->num_nodes];
00162 
00163   /* Reset the first edge starting at the new node */
00164   new_edges[this->num_nodes].next_edge = INVALID_NODE;
00165 
00166   for (NodeID i = 0; i <= this->num_nodes; ++i) {
00167     uint distance = DistanceManhattan(st->xy, Station::Get(this->nodes[i].station)->xy);
00168     new_edges[i].Init(distance);
00169     this->edges[i][this->num_nodes].Init(distance);
00170   }
00171   return this->num_nodes++;
00172 }
00173 
00180 inline void LinkGraph::AddEdge(NodeID from, NodeID to, uint capacity)
00181 {
00182   assert(from != to && from < this->num_nodes && to < this->num_nodes);
00183   Edge &edge = this->edges[from][to];
00184   Edge &first = this->edges[from][from];
00185   edge.capacity = capacity;
00186   edge.next_edge = first.next_edge;
00187   first.next_edge = to;
00188   edge.last_update = _date;
00189 }
00190 
00191 void LinkGraph::RemoveEdge(NodeID from, NodeID to)
00192 {
00193   if (from == to) return;
00194   Edge &edge = this->edges[from][to];
00195   edge.capacity = 0;
00196   edge.last_update = INVALID_DATE;
00197   edge.usage = 0;
00198 
00199   NodeID prev = from;
00200   NodeID next = this->GetFirstEdge(from);
00201   while (next != INVALID_NODE) {
00202     if (next == to) {
00203       /* Will be removed, skip it. */
00204       next = this->edges[from][prev].next_edge = edge.next_edge;
00205       break;
00206     } else {
00207       prev = next;
00208       next = this->edges[from][next].next_edge;
00209     }
00210   }
00211 }
00212 
00221 void LinkGraph::UpdateEdge(NodeID from, NodeID to, uint capacity, uint usage)
00222 {
00223   Edge &edge = this->edges[from][to];
00224   if (edge.capacity == 0) {
00225     this->AddEdge(from, to, capacity);
00226     if (usage != UINT_MAX) edge.usage += usage;
00227   } else {
00228     if (usage == UINT_MAX) {
00229       edge.capacity = max(edge.capacity, capacity);
00230     } else {
00231       assert(capacity >= usage);
00232       edge.capacity += capacity;
00233       edge.usage += usage;
00234     }
00235     edge.last_update = _date;
00236   }
00237 }
00238 
00248 void LinkGraph::SetSize()
00249 {
00250   if (this->nodes.Length() < this->num_nodes) {
00251     this->edges.Resize(this->num_nodes, this->num_nodes);
00252     this->nodes.Resize(this->num_nodes);
00253   }
00254 
00255   for (uint i = 0; i < this->num_nodes; ++i) {
00256     this->nodes[i].Init();
00257     Edge *column = this->edges[i];
00258     for (uint j = 0; j < this->num_nodes; ++j) {
00259       column[j].Init();
00260     }
00261   }
00262 }
00263 
00270 LinkGraphJob::LinkGraphJob(const LinkGraph &orig) :
00271     /* Copying the link graph here also copies its index member.
00272      * This is on purpose. */
00273     link_graph(orig),
00274     settings(_settings_game.linkgraph),
00275     thread(NULL),
00276     join_date(_date + _settings_game.linkgraph.recalc_time)
00277 {
00278 }
00279 
00283 LinkGraphJob::~LinkGraphJob()
00284 {
00285   assert(this->thread == NULL);
00286   uint size = this->link_graph.GetSize();
00287   for (NodeID node_id = 0; node_id < size; ++node_id) {
00288     StationID &station = this->link_graph.GetNode(node_id).station;
00289     if (!Station::IsValidID(station)) {
00290       /* Station got removed during the link graph run. We have to remove all
00291        * flows pointing to it now. This is costly but it should be rare. */
00292       for (NodeID from_id = 0; from_id < size; ++from_id) {
00293         if (this->link_graph.GetEdge(from_id, node_id).capacity > 0) {
00294           FlowStatMap &flows = this->nodes[from_id].flows;
00295           for (FlowStatMap::iterator it(flows.begin()); it != flows.end(); ++it) {
00296             it->second.ChangeShare(station, INT_MIN);
00297           }
00298         }
00299       }
00300       station = INVALID_STATION;
00301     }
00302   }
00303   for (NodeID node_id = 0; node_id < size; ++node_id) {
00304     StationID station = this->link_graph.GetNode(node_id).station;
00305     if (station != INVALID_STATION) {
00306       InvalidateWindowData(WC_STATION_VIEW, station, this->link_graph.GetCargo());
00307       Station::Get(station)->goods[this->link_graph.GetCargo()].flows.
00308           swap(this->GetNode(node_id).flows);
00309     }
00310   }
00311 }
00312 
00316 void LinkGraphSchedule::SpawnNext()
00317 {
00318   if (this->schedule.empty()) return;
00319   LinkGraph *next = this->schedule.front();
00320   assert(next == LinkGraph::Get(next->index));
00321   this->schedule.pop_front();
00322   if (LinkGraphJob::CanAllocateItem()) {
00323     LinkGraphJob *job = new LinkGraphJob(*next);
00324     job->SpawnThread();
00325     this->running.push_back(job);
00326   } else {
00327     DEBUG(misc, 0, "Can't allocate link graph job");
00328   }
00329 }
00330 
00334 void LinkGraphSchedule::JoinNext()
00335 {
00336   if (this->running.empty()) return;
00337   LinkGraphJob *next = this->running.front();
00338   if (!next->IsFinished()) return;
00339   this->running.pop_front();
00340   LinkGraphID id = next->Graph().index;
00341   next->JoinThread();
00342   delete next;
00343   if (LinkGraph::IsValidID(id)) {
00344     LinkGraph *lg = LinkGraph::Get(id);
00345     this->Unqueue(lg); // Unqueue to avoid double-queueing recycled IDs.
00346     this->Queue(lg);
00347   }
00348 }
00349 
00354 /* static */ void LinkGraphSchedule::Run(void *j)
00355 {
00356   LinkGraphJob *job = (LinkGraphJob *)j;
00357   LinkGraphSchedule *schedule = LinkGraphSchedule::Instance();
00358   for (uint i = 0; i < lengthof(schedule->handlers); ++i) {
00359     schedule->handlers[i]->Run(job);
00360   }
00361 }
00362 
00366 void LinkGraphJob::JoinThread()
00367 {
00368   if (this->thread != NULL) {
00369     this->thread->Join();
00370     delete this->thread;
00371     this->thread = NULL;
00372   }
00373 }
00374 
00379 void LinkGraphJob::SpawnThread()
00380 {
00381   assert(this->thread == NULL);
00382   if (!ThreadObject::New(&(LinkGraphSchedule::Run), this, &(this->thread))) {
00383     this->thread = NULL;
00384     /* Of course this will hang a bit.
00385      * On the other hand, if you want to play games which make this hang noticably
00386      * on a platform without threads then you'll probably get other problems first.
00387      * OK:
00388      * If someone comes and tells me that this hangs for him/her, I'll implement a
00389      * smaller grained "Step" method for all handlers and add some more ticks where
00390      * "Step" is called. No problem in principle.
00391      */
00392     LinkGraphSchedule::Run(this);
00393   }
00394 }
00395 
00400 void LinkGraphSchedule::SpawnAll()
00401 {
00402   for (JobList::iterator i = this->running.begin(); i != this->running.end(); ++i) {
00403     (*i)->SpawnThread();
00404   }
00405 }
00406 
00410 /* static */ void LinkGraphSchedule::Clear()
00411 {
00412   LinkGraphSchedule *inst = LinkGraphSchedule::Instance();
00413   for (JobList::iterator i(inst->running.begin()); i != inst->running.end(); ++i) {
00414     (*i)->JoinThread();
00415   }
00416   inst->running.clear();
00417   inst->schedule.clear();
00418 }
00419 
00423 LinkGraphSchedule::LinkGraphSchedule()
00424 {
00425   this->handlers[0] = new InitHandler;
00426   this->handlers[1] = new DemandHandler;
00427   this->handlers[2] = new MCFHandler<MCF1stPass>;
00428   this->handlers[3] = new FlowMapper;
00429   this->handlers[4] = new MCFHandler<MCF2ndPass>;
00430   this->handlers[5] = new FlowMapper;
00431 }
00432 
00436 LinkGraphSchedule::~LinkGraphSchedule()
00437 {
00438   this->Clear();
00439   for (uint i = 0; i < lengthof(this->handlers); ++i) {
00440     delete this->handlers[i];
00441   }
00442 }
00443 
00447 /* static */ LinkGraphSchedule *LinkGraphSchedule::Instance()
00448 {
00449   static LinkGraphSchedule inst;
00450   return &inst;
00451 }
00452 
00456 void OnTick_LinkGraph()
00457 {
00458   if (_date_fract == LinkGraphSchedule::SPAWN_JOIN_TICK) {
00459     Date offset = _date % _settings_game.linkgraph.recalc_interval;
00460     if (offset == 0) {
00461       LinkGraphSchedule::Instance()->SpawnNext();
00462     } else if (offset == _settings_game.linkgraph.recalc_interval / 2) {
00463       LinkGraphSchedule::Instance()->JoinNext();
00464     }
00465   } else if (_date_fract == LinkGraph::COMPRESSION_TICK) {
00466     LinkGraph *lg;
00467     /* Compress graphs after 256 to 512 days; approximately once a year. */
00468     int cutoff = RandomRange(256) + 256;
00469     FOR_ALL_LINK_GRAPHS(lg) {
00470       if (_date - lg->GetLastCompression() > cutoff) {
00471         lg->Compress();
00472         break;
00473       }
00474     }
00475   }
00476 }
00477 
00486 void Path::Fork(Path *base, uint cap, int free_cap, uint dist)
00487 {
00488   this->capacity = min(base->capacity, cap);
00489   this->free_capacity = min(base->free_capacity, free_cap);
00490   this->distance = base->distance + dist;
00491   assert(this->distance > 0);
00492   if (this->parent != base) {
00493     this->Detach();
00494     this->parent = base;
00495     this->parent->num_children++;
00496   }
00497   this->origin = base->origin;
00498 }
00499 
00508 uint Path::AddFlow(uint new_flow, LinkGraphJob *job, uint max_saturation)
00509 {
00510   if (this->parent != NULL) {
00511     EdgeAnnotation &edge = job->GetEdge(this->parent->node, this->node);
00512     if (max_saturation != UINT_MAX) {
00513       uint usable_cap = job->Graph().GetEdge(this->parent->node, this->node).capacity *
00514           max_saturation / 100;
00515       if (usable_cap > edge.flow) {
00516         new_flow = min(new_flow, usable_cap - edge.flow);
00517       } else {
00518         return 0;
00519       }
00520     }
00521     new_flow = this->parent->AddFlow(new_flow, job, max_saturation);
00522     if (new_flow > 0) {
00523       job->GetNode(this->parent->node).paths.insert(this);
00524     }
00525     edge.flow += new_flow;
00526   }
00527   this->flow += new_flow;
00528   return new_flow;
00529 }
00530 
00536 Path::Path(NodeID n, bool source) :
00537   distance(source ? 0 : UINT_MAX),
00538   capacity(0),
00539   free_capacity(source ? INT_MAX : INT_MIN),
00540   flow(0), node(n), origin(source ? n : INVALID_NODE),
00541   num_children(0), parent(NULL)
00542 {}
00543