00001
00002
00003
00004
00005
00006
00007
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
00027 LinkGraphPool _link_graph_pool("LinkGraph");
00028 INSTANTIATE_POOL_METHODS(LinkGraph)
00029
00030
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
00134
00135
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
00153
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
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
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
00272
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
00291
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);
00346 this->Queue(lg);
00347 }
00348 }
00349
00354 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
00385
00386
00387
00388
00389
00390
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 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 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
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