OpenTTD Source: src/linkgraph/linkgraph.cpp Source File

OpenTTD Source 13.2.1

linkgraph.cpp
Go to the documentation of this file.
1 /*
2 * This file is part of OpenTTD.
3 * 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.
4 * 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.
5 * 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/>.
6 */
7
10 #include "../stdafx.h"
11 #include "../core/pool_func.hpp"
12 #include "linkgraph.h"
13
14 #include "../safeguards.h"
15
16 /* Initialize the link-graph-pool */
17 LinkGraphPool _link_graph_pool("LinkGraph");
18 INSTANTIATE_POOL_METHODS(LinkGraph)
19
20
26 inline void LinkGraph::BaseNode::Init(TileIndex xy, StationID st, uint demand)
27 {
28 this->xy = xy;
29 this->supply = 0;
30 this->demand = demand;
31 this->station = st;
32 this->last_update = INVALID_DATE;
33 }
34
38 inline void LinkGraph::BaseEdge::Init()
39 {
40 this->capacity = 0;
41 this->usage = 0;
42 this->travel_time_sum = 0;
43 this->last_unrestricted_update = INVALID_DATE;
44 this->last_restricted_update = INVALID_DATE;
45 this->next_edge = INVALID_NODE;
46 }
47
53 void LinkGraph::ShiftDates(int interval)
54 {
55 this->last_compression += interval;
56 for (NodeID node1 = 0; node1 < this->Size(); ++node1) {
57 BaseNode &source = this->nodes[node1];
58 if (source.last_update != INVALID_DATE) source.last_update += interval;
59 for (NodeID node2 = 0; node2 < this->Size(); ++node2) {
60 BaseEdge &edge = this->edges[node1][node2];
61 if (edge.last_unrestricted_update != INVALID_DATE) edge.last_unrestricted_update += interval;
62 if (edge.last_restricted_update != INVALID_DATE) edge.last_restricted_update += interval;
63 }
64 }
65 }
66
67 void LinkGraph::Compress()
68 {
69 this->last_compression = (_date + this->last_compression) / 2;
70 for (NodeID node1 = 0; node1 < this->Size(); ++node1) {
71 this->nodes[node1].supply /= 2;
72 for (NodeID node2 = 0; node2 < this->Size(); ++node2) {
73 BaseEdge &edge = this->edges[node1][node2];
74 if (edge.capacity > 0) {
75 uint new_capacity = std::max(1U, edge.capacity / 2);
76 if (edge.capacity < (1 << 16)) {
77 edge.travel_time_sum = edge.travel_time_sum * new_capacity / edge.capacity;
78 } else if (edge.travel_time_sum != 0) {
79 edge.travel_time_sum = std::max(1ULL, edge.travel_time_sum / 2);
80 }
81 edge.capacity = new_capacity;
82 edge.usage /= 2;
83 }
84 }
85 }
86 }
87
92 void LinkGraph::Merge(LinkGraph *other)
93 {
94 Date age = _date - this->last_compression + 1;
95 Date other_age = _date - other->last_compression + 1;
96 NodeID first = this->Size();
97 for (NodeID node1 = 0; node1 < other->Size(); ++node1) {
98 Station *st = Station::Get(other->nodes[node1].station);
99 NodeID new_node = this->AddNode(st);
100 this->nodes[new_node].supply = LinkGraph::Scale(other->nodes[node1].supply, age, other_age);
101 st->goods[this->cargo].link_graph = this->index;
102 st->goods[this->cargo].node = new_node;
103 for (NodeID node2 = 0; node2 < node1; ++node2) {
104 BaseEdge &forward = this->edges[new_node][first + node2];
105 BaseEdge &backward = this->edges[first + node2][new_node];
106 forward = other->edges[node1][node2];
107 backward = other->edges[node2][node1];
108 forward.capacity = LinkGraph::Scale(forward.capacity, age, other_age);
109 forward.usage = LinkGraph::Scale(forward.usage, age, other_age);
110 forward.travel_time_sum = LinkGraph::Scale(forward.travel_time_sum, age, other_age);
111 if (forward.next_edge != INVALID_NODE) forward.next_edge += first;
112 backward.capacity = LinkGraph::Scale(backward.capacity, age, other_age);
113 backward.usage = LinkGraph::Scale(backward.usage, age, other_age);
114 backward.travel_time_sum = LinkGraph::Scale(backward.travel_time_sum, age, other_age);
115 if (backward.next_edge != INVALID_NODE) backward.next_edge += first;
116 }
117 BaseEdge &new_start = this->edges[new_node][new_node];
118 new_start = other->edges[node1][node1];
119 if (new_start.next_edge != INVALID_NODE) new_start.next_edge += first;
120 }
121 delete other;
122 }
123
128 void LinkGraph::RemoveNode(NodeID id)
129 {
130 assert(id < this->Size());
131
132 NodeID last_node = this->Size() - 1;
133 for (NodeID i = 0; i <= last_node; ++i) {
134 (*this)[i].RemoveEdge(id);
135 BaseEdge *node_edges = this->edges[i];
136 NodeID prev = i;
137 NodeID next = node_edges[i].next_edge;
138 while (next != INVALID_NODE) {
139 if (next == last_node) {
140 node_edges[prev].next_edge = id;
141 break;
142 }
143 prev = next;
144 next = node_edges[prev].next_edge;
145 }
146 node_edges[id] = node_edges[last_node];
147 }
148 Station::Get(this->nodes[last_node].station)->goods[this->cargo].node = id;
149 /* Erase node by swapping with the last element. Node index is referenced
150 * directly from station goods entries so the order and position must remain. */
151 this->nodes[id] = this->nodes.back();
152 this->nodes.pop_back();
153 this->edges.EraseColumn(id);
154 /* Not doing EraseRow here, as having the extra invalid row doesn't hurt
155 * and removing it would trigger a lot of memmove. The data has already
156 * been copied around in the loop above. */
157 }
158
167 NodeID LinkGraph::AddNode(const Station *st)
168 {
169 const GoodsEntry &good = st->goods[this->cargo];
170
171 NodeID new_node = this->Size();
172 this->nodes.emplace_back();
173 /* Avoid reducing the height of the matrix as that is expensive and we
174 * most likely will increase it again later which is again expensive. */
175 this->edges.Resize(new_node + 1U, std::max(new_node + 1U, this->edges.Height()));
176
177 this->nodes[new_node].Init(st->xy, st->index,
178 HasBit(good.status, GoodsEntry::GES_ACCEPTANCE));
179
180 BaseEdge *new_edges = this->edges[new_node];
181
182 /* Reset the first edge starting at the new node */
183 new_edges[new_node].next_edge = INVALID_NODE;
184
185 for (NodeID i = 0; i <= new_node; ++i) {
186 new_edges[i].Init();
187 this->edges[i][new_node].Init();
188 }
189 return new_node;
190 }
191
200 void LinkGraph::Node::AddEdge(NodeID to, uint capacity, uint usage, uint32 travel_time, EdgeUpdateMode mode)
201 {
202 assert(this->index != to);
203 BaseEdge &edge = this->edges[to];
204 BaseEdge &first = this->edges[this->index];
205 edge.capacity = capacity;
206 edge.usage = usage;
207 edge.travel_time_sum = travel_time * capacity;
208 edge.next_edge = first.next_edge;
209 first.next_edge = to;
210 if (mode & EUM_UNRESTRICTED) edge.last_unrestricted_update = _date;
211 if (mode & EUM_RESTRICTED) edge.last_restricted_update = _date;
212 }
213
221 void LinkGraph::Node::UpdateEdge(NodeID to, uint capacity, uint usage, uint32 travel_time, EdgeUpdateMode mode)
222 {
223 assert(capacity > 0);
224 assert(usage <= capacity);
225 if (this->edges[to].capacity == 0) {
226 this->AddEdge(to, capacity, usage, travel_time, mode);
227 } else {
228 (*this)[to].Update(capacity, usage, travel_time, mode);
229 }
230 }
231
236 void LinkGraph::Node::RemoveEdge(NodeID to)
237 {
238 if (this->index == to) return;
239 BaseEdge &edge = this->edges[to];
240 edge.capacity = 0;
241 edge.last_unrestricted_update = INVALID_DATE;
242 edge.last_restricted_update = INVALID_DATE;
243 edge.usage = 0;
244 edge.travel_time_sum = 0;
245
246 NodeID prev = this->index;
247 NodeID next = this->edges[this->index].next_edge;
248 while (next != INVALID_NODE) {
249 if (next == to) {
250 /* Will be removed, skip it. */
251 this->edges[prev].next_edge = edge.next_edge;
252 edge.next_edge = INVALID_NODE;
253 break;
254 } else {
255 prev = next;
256 next = this->edges[next].next_edge;
257 }
258 }
259 }
260
271 void LinkGraph::Edge::Update(uint capacity, uint usage, uint32 travel_time, EdgeUpdateMode mode)
272 {
273 assert(this->edge.capacity > 0);
274 assert(capacity >= usage);
275
276 if (mode & EUM_INCREASE) {
277 if (this->edge.travel_time_sum == 0) {
278 this->edge.travel_time_sum = (this->edge.capacity + capacity) * travel_time;
279 } else if (travel_time == 0) {
280 this->edge.travel_time_sum += this->edge.travel_time_sum / this->edge.capacity * capacity;
281 } else {
282 this->edge.travel_time_sum += travel_time * capacity;
283 }
284 this->edge.capacity += capacity;
285 this->edge.usage += usage;
286 } else if (mode & EUM_REFRESH) {
287 if (this->edge.travel_time_sum == 0) {
288 this->edge.capacity = std::max(this->edge.capacity, capacity);
289 this->edge.travel_time_sum = travel_time * this->edge.capacity;
290 } else if (capacity > this->edge.capacity) {
291 this->edge.travel_time_sum = this->edge.travel_time_sum / this->edge.capacity * capacity;
292 this->edge.capacity = capacity;
293 }
294 this->edge.usage = std::max(this->edge.usage, usage);
295 }
296 if (mode & EUM_UNRESTRICTED) this->edge.last_unrestricted_update = _date;
297 if (mode & EUM_RESTRICTED) this->edge.last_restricted_update = _date;
298 }
299
305 void LinkGraph::Init(uint size)
306 {
307 assert(this->Size() == 0);
308 this->edges.Resize(size, size);
309 this->nodes.resize(size);
310
311 for (uint i = 0; i < size; ++i) {
312 this->nodes[i].Init();
313 BaseEdge *column = this->edges[i];
314 for (uint j = 0; j < size; ++j) column[j].Init();
315 }
316 }
Station::goods
GoodsEntry goods[NUM_CARGO]
Goods at this station.
Definition: station_base.h:483
LinkGraph::edges
EdgeMatrix edges
Edges in the component.
Definition: linkgraph.h:546
LinkGraph
A connected component of a link graph.
Definition: linkgraph.h:39
LinkGraph::BaseEdge::usage
uint usage
Usage of the link.
Definition: linkgraph.h:64
LinkGraph::nodes
NodeVector nodes
Nodes in the component.
Definition: linkgraph.h:545
Station
Station data structure.
Definition: station_base.h:454
EUM_UNRESTRICTED
@ EUM_UNRESTRICTED
Use unrestricted link.
Definition: linkgraph_type.h:56
Pool::PoolItem<&_link_graph_pool >::index
Tindex index
Index of this pool item.
Definition: pool_type.hpp:235
HasBit
static bool HasBit(const T x, const uint8 y)
Checks if a bit in a value is set.
Definition: bitmath_func.hpp:103
TileIndex
The index/ID of a Tile.
Definition: tile_type.h:85
LinkGraph::BaseEdge::Init
void Init()
Create an edge.
Definition: linkgraph.cpp:38
LinkGraph::Scale
static uint Scale(uint val, uint target_age, uint orig_age)
Scale a value from a link graph of age orig_age for usage in one of age target_age.
Definition: linkgraph.h:464
EUM_INCREASE
@ EUM_INCREASE
Increase capacity.
Definition: linkgraph_type.h:53
SpecializedStation< Station, false >::Get
static Station * Get(size_t index)
Gets station with given index.
Definition: base_station_base.h:218
LinkGraph::Size
NodeID Size() const
Get the current size of the component.
Definition: linkgraph.h:508
LinkGraph::RemoveNode
void RemoveNode(NodeID id)
Remove a node from the link graph by overwriting it with the last node.
Definition: linkgraph.cpp:128
LinkGraph::Node::UpdateEdge
void UpdateEdge(NodeID to, uint capacity, uint usage, uint32 time, EdgeUpdateMode mode)
Creates an edge if none exists yet or updates an existing edge.
Definition: linkgraph.cpp:221
LinkGraph::Init
void Init(uint size)
Resize the component and fill it with empty nodes and edges.
Definition: linkgraph.cpp:305
GoodsEntry::status
byte status
Status of this cargo, see GoodsEntryStatus.
Definition: station_base.h:223
EdgeUpdateMode
EdgeUpdateMode
Special modes for updating links.
Definition: linkgraph_type.h:52
LinkGraph::BaseNode::last_update
Date last_update
When the supply was last updated.
Definition: linkgraph.h:52
SmallMatrix::Resize
void Resize(uint new_width, uint new_height)
Set the size to a specific width and height, preserving item positions as far as possible in the proc...
Definition: smallmatrix_type.hpp:214
_date
Date _date
Current date in days (day counter)
Definition: date.cpp:28
LinkGraph::BaseEdge::capacity
uint capacity
Capacity of the link.
Definition: linkgraph.h:63
GoodsEntry::node
NodeID node
ID of node in link graph referring to this goods entry.
Definition: station_base.h:255
Date
int32 Date
The type to store our dates in.
Definition: date_type.h:14
LinkGraph::BaseEdge
An edge in the link graph.
Definition: linkgraph.h:62
SmallMatrix::EraseColumn
void EraseColumn(uint x)
Erase a column, replacing it with the last one.
Definition: smallmatrix_type.hpp:131
GoodsEntry::link_graph
LinkGraphID link_graph
Link graph this station belongs to.
Definition: station_base.h:254
EUM_REFRESH
@ EUM_REFRESH
Refresh capacity.
Definition: linkgraph_type.h:54
_link_graph_pool
LinkGraphPool _link_graph_pool("LinkGraph")
The actual pool with link graphs.
LinkGraph::Edge::Update
void Update(uint capacity, uint usage, uint32 time, EdgeUpdateMode mode)
Update an edge.
Definition: linkgraph.cpp:271
LinkGraph::Node::AddEdge
void AddEdge(NodeID to, uint capacity, uint usage, uint32 time, EdgeUpdateMode mode)
Fill an edge with values from a link.
Definition: linkgraph.cpp:200
LinkGraph::ShiftDates
void ShiftDates(int interval)
Shift all dates by given interval.
Definition: linkgraph.cpp:53
LinkGraph::BaseEdge::last_unrestricted_update
Date last_unrestricted_update
When the unrestricted part of the link was last updated.
Definition: linkgraph.h:66
GoodsEntry
Stores station stats for a single cargo.
Definition: station_base.h:167
Pool
Base class for all pools.
Definition: pool_type.hpp:81
LinkGraph::AddNode
NodeID AddNode(const Station *st)
Add a node to the component and create empty edges associated with it.
Definition: linkgraph.cpp:167
LinkGraph::Node::RemoveEdge
void RemoveEdge(NodeID to)
Remove an outgoing edge from this node.
Definition: linkgraph.cpp:236
INVALID_DATE
static const Date INVALID_DATE
Representation of an invalid date.
Definition: date_type.h:111
LinkGraph::cargo
CargoID cargo
Cargo of this component's link graph.
Definition: linkgraph.h:543
LinkGraph::last_compression
Date last_compression
Last time the capacities and supplies were compressed.
Definition: linkgraph.h:544
GoodsEntry::GES_ACCEPTANCE
@ GES_ACCEPTANCE
Set when the station accepts the cargo currently for final deliveries.
Definition: station_base.h:174
linkgraph.h
LinkGraph::BaseEdge::travel_time_sum
uint64 travel_time_sum
Sum of the travel times of the link, in ticks.
Definition: linkgraph.h:65
LinkGraph::Merge
void Merge(LinkGraph *other)
Merge a link graph with another one.
Definition: linkgraph.cpp:92
BaseStation::xy
TileIndex xy
Base tile of the station.
Definition: base_station_base.h:53
EUM_RESTRICTED
@ EUM_RESTRICTED
Use restricted link.
Definition: linkgraph_type.h:55
INSTANTIATE_POOL_METHODS
#define INSTANTIATE_POOL_METHODS(name)
Force instantiation of pool methods so we don't get linker errors.
Definition: pool_func.hpp:224
LinkGraph::BaseEdge::last_restricted_update
Date last_restricted_update
When the restricted part of the link was last updated.
Definition: linkgraph.h:67
LinkGraph::BaseNode
Node of the link graph.
Definition: linkgraph.h:47
LinkGraph::BaseEdge::next_edge
NodeID next_edge
Destination of next valid edge starting at the same source node.
Definition: linkgraph.h:68