Linkgraph: Use sparse storage format for edge annotations
Copy relevant parts of base edge into edge annotation
This commit is contained in:
@@ -37,7 +37,7 @@ static DateTicks GetLinkGraphJobJoinDateTicks(uint duration_multiplier)
|
||||
|
||||
/**
|
||||
* Create a link graph job from a link graph. The link graph will be copied so
|
||||
* that the calculations don't interfer with the normal operations on the
|
||||
* that the calculations don't interfere with the normal operations on the
|
||||
* original. The job is immediately started.
|
||||
* @param orig Original LinkGraph to be copied.
|
||||
*/
|
||||
@@ -125,13 +125,13 @@ void LinkGraphJob::FinaliseJob()
|
||||
LinkGraph *lg = LinkGraph::Get(ge.link_graph);
|
||||
FlowStatMap &flows = from.Flows();
|
||||
|
||||
this->IterateEdgesFromNode(from, [&](NodeID from_id, NodeID to_id, Edge edge) {
|
||||
if (edge.Flow() == 0) return;
|
||||
StationID to = (*this)[to_id].Station();
|
||||
for (Edge &edge : from.GetEdges()) {
|
||||
if (edge.Flow() == 0) continue;
|
||||
StationID to = (*this)[edge.To()].Station();
|
||||
Station *st2 = Station::GetIfValid(to);
|
||||
LinkGraph::ConstEdge lg_edge = lg->GetConstEdge(from_id, to_id);
|
||||
LinkGraph::ConstEdge lg_edge = lg->GetConstEdge(edge.From(), edge.To());
|
||||
if (st2 == nullptr || st2->goods[this->Cargo()].link_graph != this->link_graph.index ||
|
||||
st2->goods[this->Cargo()].node != to_id ||
|
||||
st2->goods[this->Cargo()].node != edge.To() ||
|
||||
lg_edge.LastUpdate() == INVALID_DATE) {
|
||||
/* Edge has been removed. Delete flows. */
|
||||
StationIDStack erased = flows.DeleteFlows(to);
|
||||
@@ -143,7 +143,7 @@ void LinkGraphJob::FinaliseJob()
|
||||
/* Edge is fully restricted. */
|
||||
flows.RestrictFlows(to);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* Swap shares and invalidate ones that are completely deleted. Don't
|
||||
* really delete them as we could then end up with unroutable cargo
|
||||
@@ -197,22 +197,62 @@ void LinkGraphJob::Init()
|
||||
{
|
||||
uint size = this->Size();
|
||||
this->nodes.resize(size);
|
||||
this->edges.Resize(size, size);
|
||||
for (uint i = 0; i < size; ++i) {
|
||||
this->nodes[i].Init(this->link_graph[i].Supply());
|
||||
EdgeAnnotation *node_edges = this->edges[i];
|
||||
for (uint j = 0; j < size; ++j) {
|
||||
node_edges[j].Init();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a linkgraph job edge.
|
||||
*/
|
||||
void LinkGraphJob::EdgeAnnotation::Init()
|
||||
{
|
||||
this->flow = 0;
|
||||
/* Prioritize the fastest route for passengers, mail and express cargo,
|
||||
* and the shortest route for other classes of cargo.
|
||||
* In-between stops are punished with a 1 tile or 1 day penalty. */
|
||||
const bool express = IsLinkGraphCargoExpress(this->Cargo());
|
||||
const uint16 aircraft_link_scale = this->Settings().aircraft_link_scale;
|
||||
|
||||
size_t edge_count = 0;
|
||||
for (auto &it : this->link_graph.GetEdges()) {
|
||||
if (it.first.first == it.first.second) continue;
|
||||
edge_count++;
|
||||
}
|
||||
|
||||
this->edges.resize(edge_count);
|
||||
size_t start_idx = 0;
|
||||
size_t idx = 0;
|
||||
NodeID last_from = INVALID_NODE;
|
||||
auto flush = [&]() {
|
||||
if (last_from == INVALID_NODE) return;
|
||||
this->nodes[last_from].edges = { this->edges.data() + start_idx, idx - start_idx };
|
||||
};
|
||||
for (auto &it : this->link_graph.GetEdges()) {
|
||||
if (it.first.first == it.first.second) continue;
|
||||
|
||||
if (it.first.first != last_from) {
|
||||
flush();
|
||||
last_from = it.first.first;
|
||||
start_idx = idx;
|
||||
}
|
||||
|
||||
LinkGraph::ConstEdge edge(it.second);
|
||||
|
||||
auto calculate_distance = [&]() {
|
||||
return DistanceMaxPlusManhattan((*this)[it.first.first].XY(), (*this)[it.first.second].XY()) + 1;
|
||||
};
|
||||
|
||||
uint distance_anno;
|
||||
if (express) {
|
||||
/* Compute a default travel time from the distance and an average speed of 1 tile/day. */
|
||||
distance_anno = (edge.TravelTime() != 0) ? edge.TravelTime() + DAY_TICKS : calculate_distance() * DAY_TICKS;
|
||||
} else {
|
||||
distance_anno = calculate_distance();
|
||||
}
|
||||
|
||||
if (edge.LastAircraftUpdate() != INVALID_DATE && aircraft_link_scale > 100) {
|
||||
distance_anno *= aircraft_link_scale;
|
||||
distance_anno /= 100;
|
||||
}
|
||||
|
||||
this->edges[idx].InitEdge(it.first.first, it.first.second, edge.Capacity(), distance_anno);
|
||||
idx++;
|
||||
}
|
||||
flush();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -259,7 +299,7 @@ void Path::Fork(Path *base, uint cap, int free_cap, uint dist)
|
||||
uint Path::AddFlow(uint new_flow, LinkGraphJob &job, uint max_saturation)
|
||||
{
|
||||
if (this->GetParent() != nullptr) {
|
||||
LinkGraphJob::Edge edge = job[this->GetParent()->node].MakeEdge(job, this->node);
|
||||
LinkGraphJob::Edge &edge = job[this->GetParent()->node].GetEdgeTo(this->node);
|
||||
if (max_saturation != UINT_MAX) {
|
||||
uint usable_cap = edge.Capacity() * max_saturation / 100;
|
||||
if (usable_cap > edge.Flow()) {
|
||||
|
Reference in New Issue
Block a user