Linkgraph: Use sparse storage format for edge annotations
Copy relevant parts of base edge into edge annotation
This commit is contained in:
@@ -12,7 +12,6 @@
|
|||||||
|
|
||||||
#include "../core/pool_type.hpp"
|
#include "../core/pool_type.hpp"
|
||||||
#include "../core/smallmap_type.hpp"
|
#include "../core/smallmap_type.hpp"
|
||||||
#include "../core/smallmatrix_type.hpp"
|
|
||||||
#include "../core/bitmath_func.hpp"
|
#include "../core/bitmath_func.hpp"
|
||||||
#include "../station_base.h"
|
#include "../station_base.h"
|
||||||
#include "../cargotype.h"
|
#include "../cargotype.h"
|
||||||
|
@@ -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
|
* 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.
|
* original. The job is immediately started.
|
||||||
* @param orig Original LinkGraph to be copied.
|
* @param orig Original LinkGraph to be copied.
|
||||||
*/
|
*/
|
||||||
@@ -125,13 +125,13 @@ void LinkGraphJob::FinaliseJob()
|
|||||||
LinkGraph *lg = LinkGraph::Get(ge.link_graph);
|
LinkGraph *lg = LinkGraph::Get(ge.link_graph);
|
||||||
FlowStatMap &flows = from.Flows();
|
FlowStatMap &flows = from.Flows();
|
||||||
|
|
||||||
this->IterateEdgesFromNode(from, [&](NodeID from_id, NodeID to_id, Edge edge) {
|
for (Edge &edge : from.GetEdges()) {
|
||||||
if (edge.Flow() == 0) return;
|
if (edge.Flow() == 0) continue;
|
||||||
StationID to = (*this)[to_id].Station();
|
StationID to = (*this)[edge.To()].Station();
|
||||||
Station *st2 = Station::GetIfValid(to);
|
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 ||
|
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) {
|
lg_edge.LastUpdate() == INVALID_DATE) {
|
||||||
/* Edge has been removed. Delete flows. */
|
/* Edge has been removed. Delete flows. */
|
||||||
StationIDStack erased = flows.DeleteFlows(to);
|
StationIDStack erased = flows.DeleteFlows(to);
|
||||||
@@ -143,7 +143,7 @@ void LinkGraphJob::FinaliseJob()
|
|||||||
/* Edge is fully restricted. */
|
/* Edge is fully restricted. */
|
||||||
flows.RestrictFlows(to);
|
flows.RestrictFlows(to);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
/* Swap shares and invalidate ones that are completely deleted. Don't
|
/* Swap shares and invalidate ones that are completely deleted. Don't
|
||||||
* really delete them as we could then end up with unroutable cargo
|
* really delete them as we could then end up with unroutable cargo
|
||||||
@@ -197,22 +197,62 @@ void LinkGraphJob::Init()
|
|||||||
{
|
{
|
||||||
uint size = this->Size();
|
uint size = this->Size();
|
||||||
this->nodes.resize(size);
|
this->nodes.resize(size);
|
||||||
this->edges.Resize(size, size);
|
|
||||||
for (uint i = 0; i < size; ++i) {
|
for (uint i = 0; i < size; ++i) {
|
||||||
this->nodes[i].Init(this->link_graph[i].Supply());
|
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/* Prioritize the fastest route for passengers, mail and express cargo,
|
||||||
* Initialize a linkgraph job edge.
|
* and the shortest route for other classes of cargo.
|
||||||
*/
|
* In-between stops are punished with a 1 tile or 1 day penalty. */
|
||||||
void LinkGraphJob::EdgeAnnotation::Init()
|
const bool express = IsLinkGraphCargoExpress(this->Cargo());
|
||||||
{
|
const uint16 aircraft_link_scale = this->Settings().aircraft_link_scale;
|
||||||
this->flow = 0;
|
|
||||||
|
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)
|
uint Path::AddFlow(uint new_flow, LinkGraphJob &job, uint max_saturation)
|
||||||
{
|
{
|
||||||
if (this->GetParent() != nullptr) {
|
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) {
|
if (max_saturation != UINT_MAX) {
|
||||||
uint usable_cap = edge.Capacity() * max_saturation / 100;
|
uint usable_cap = edge.Capacity() * max_saturation / 100;
|
||||||
if (usable_cap > edge.Flow()) {
|
if (usable_cap > edge.Flow()) {
|
||||||
|
@@ -41,15 +41,78 @@ public:
|
|||||||
uint unsatisfied_demand = 0; ///< Demand over this edge that hasn't been satisfied yet.
|
uint unsatisfied_demand = 0; ///< Demand over this edge that hasn't been satisfied yet.
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
|
||||||
/**
|
/**
|
||||||
* Annotation for a link graph flow edge.
|
* Annotation for a link graph flow edge.
|
||||||
*/
|
*/
|
||||||
struct EdgeAnnotation {
|
struct Edge {
|
||||||
|
private:
|
||||||
|
NodeID from; ///< From Node.
|
||||||
|
NodeID to; ///< To Node.
|
||||||
|
uint capacity; ///< Capacity of the link.
|
||||||
|
uint distance_anno; ///< Pre-computed distance annotation.
|
||||||
|
|
||||||
uint flow; ///< Planned flow over this edge.
|
uint flow; ///< Planned flow over this edge.
|
||||||
void Init();
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Get edge's from node.
|
||||||
|
* @return from NodeID.
|
||||||
|
*/
|
||||||
|
NodeID From() const { return this->from; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get edge's to node.
|
||||||
|
* @return to NodeID.
|
||||||
|
*/
|
||||||
|
NodeID To() const { return this->to; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get edge's capacity.
|
||||||
|
* @return Capacity.
|
||||||
|
*/
|
||||||
|
uint Capacity() const { return this->capacity; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get edge's distance annotation.
|
||||||
|
* @return Distance annotation.
|
||||||
|
*/
|
||||||
|
uint DistanceAnno() const { return this->distance_anno; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the total flow on the edge.
|
||||||
|
* @return Flow.
|
||||||
|
*/
|
||||||
|
uint Flow() const { return this->flow; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add some flow.
|
||||||
|
* @param flow Flow to be added.
|
||||||
|
*/
|
||||||
|
void AddFlow(uint flow) { this->flow += flow; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove some flow.
|
||||||
|
* @param flow Flow to be removed.
|
||||||
|
*/
|
||||||
|
void RemoveFlow(uint flow)
|
||||||
|
{
|
||||||
|
dbg_assert(flow <= this->flow);
|
||||||
|
this->flow -= flow;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitEdge(NodeID from, NodeID to, uint capacity, uint distance_anno)
|
||||||
|
{
|
||||||
|
this->from = from;
|
||||||
|
this->to = to;
|
||||||
|
this->capacity = capacity;
|
||||||
|
this->distance_anno = distance_anno;
|
||||||
|
this->flow = 0;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef std::vector<Edge> EdgeAnnotationVector;
|
||||||
|
|
||||||
|
private:
|
||||||
/**
|
/**
|
||||||
* Annotation for a link graph node.
|
* Annotation for a link graph node.
|
||||||
*/
|
*/
|
||||||
@@ -59,11 +122,11 @@ private:
|
|||||||
PathList paths; ///< Paths through this node, sorted so that those with flow == 0 are in the back.
|
PathList paths; ///< Paths through this node, sorted so that those with flow == 0 are in the back.
|
||||||
FlowStatMap flows; ///< Planned flows to other nodes.
|
FlowStatMap flows; ///< Planned flows to other nodes.
|
||||||
span<DemandAnnotation> demands; ///< Demand annotations belonging to this node.
|
span<DemandAnnotation> demands; ///< Demand annotations belonging to this node.
|
||||||
|
span<Edge> edges; ///< Edges with annotations belonging to this node.
|
||||||
void Init(uint supply);
|
void Init(uint supply);
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<NodeAnnotation> NodeAnnotationVector;
|
typedef std::vector<NodeAnnotation> NodeAnnotationVector;
|
||||||
typedef SmallMatrix<EdgeAnnotation> EdgeAnnotationMatrix;
|
|
||||||
|
|
||||||
friend SaveLoadTable GetLinkGraphJobDesc();
|
friend SaveLoadTable GetLinkGraphJobDesc();
|
||||||
friend upstream_sl::SaveLoadTable upstream_sl::GetLinkGraphJobDesc();
|
friend upstream_sl::SaveLoadTable upstream_sl::GetLinkGraphJobDesc();
|
||||||
@@ -73,12 +136,13 @@ private:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
const LinkGraph link_graph; ///< Link graph to by analyzed. Is copied when job is started and mustn't be modified later.
|
const LinkGraph link_graph; ///< Link graph to by analyzed. Is copied when job is started and mustn't be modified later.
|
||||||
|
|
||||||
std::shared_ptr<LinkGraphJobGroup> group; ///< Job group thread the job is running in or nullptr if it's running in the main thread.
|
std::shared_ptr<LinkGraphJobGroup> group; ///< Job group thread the job is running in or nullptr if it's running in the main thread.
|
||||||
const LinkGraphSettings settings; ///< Copy of _settings_game.linkgraph at spawn time.
|
const LinkGraphSettings settings; ///< Copy of _settings_game.linkgraph at spawn time.
|
||||||
DateTicks join_date_ticks; ///< Date when the job is to be joined.
|
DateTicks join_date_ticks; ///< Date when the job is to be joined.
|
||||||
DateTicks start_date_ticks; ///< Date when the job was started.
|
DateTicks start_date_ticks; ///< Date when the job was started.
|
||||||
NodeAnnotationVector nodes; ///< Extra node data necessary for link graph calculation.
|
NodeAnnotationVector nodes; ///< Extra node data necessary for link graph calculation.
|
||||||
EdgeAnnotationMatrix edges; ///< Extra edge data necessary for link graph calculation.
|
EdgeAnnotationVector edges; ///< Edge data necessary for link graph calculation.
|
||||||
std::atomic<bool> job_completed; ///< Is the job still running. This is accessed by multiple threads and reads may be stale.
|
std::atomic<bool> job_completed; ///< Is the job still running. This is accessed by multiple threads and reads may be stale.
|
||||||
std::atomic<bool> job_aborted; ///< Has the job been aborted. This is accessed by multiple threads and reads may be stale.
|
std::atomic<bool> job_aborted; ///< Has the job been aborted. This is accessed by multiple threads and reads may be stale.
|
||||||
|
|
||||||
@@ -93,59 +157,6 @@ public:
|
|||||||
|
|
||||||
DynUniformArenaAllocator path_allocator; ///< Arena allocator used for paths
|
DynUniformArenaAllocator path_allocator; ///< Arena allocator used for paths
|
||||||
|
|
||||||
/**
|
|
||||||
* An annotation-only job edge. Wraps an edge annotation. The
|
|
||||||
* annotation can be modified.
|
|
||||||
*/
|
|
||||||
class AnnoEdge {
|
|
||||||
private:
|
|
||||||
EdgeAnnotation &anno; ///< Annotation being wrapped.
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Constructor.
|
|
||||||
* @param anno Annotation to be wrapped.
|
|
||||||
*/
|
|
||||||
AnnoEdge(EdgeAnnotation &anno) :
|
|
||||||
anno(anno) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the total flow on the edge.
|
|
||||||
* @return Flow.
|
|
||||||
*/
|
|
||||||
uint Flow() const { return this->anno.flow; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add some flow.
|
|
||||||
* @param flow Flow to be added.
|
|
||||||
*/
|
|
||||||
void AddFlow(uint flow) { this->anno.flow += flow; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove some flow.
|
|
||||||
* @param flow Flow to be removed.
|
|
||||||
*/
|
|
||||||
void RemoveFlow(uint flow)
|
|
||||||
{
|
|
||||||
assert(flow <= this->anno.flow);
|
|
||||||
this->anno.flow -= flow;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A job edge. Wraps a link graph edge and an edge annotation. The
|
|
||||||
* annotation can be modified, the edge is constant.
|
|
||||||
*/
|
|
||||||
class Edge : public LinkGraph::ConstEdge, public AnnoEdge {
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Constructor.
|
|
||||||
* @param edge Link graph edge to be wrapped.
|
|
||||||
* @param anno Annotation to be wrapped.
|
|
||||||
*/
|
|
||||||
Edge(const LinkGraph::BaseEdge &edge, EdgeAnnotation &anno) :
|
|
||||||
LinkGraph::ConstEdge(edge), AnnoEdge(anno) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Link graph job node. Wraps a constant link graph node and a modifiable
|
* Link graph job node. Wraps a constant link graph node and a modifiable
|
||||||
* node annotation.
|
* node annotation.
|
||||||
@@ -153,7 +164,6 @@ public:
|
|||||||
class Node : public LinkGraph::ConstNode {
|
class Node : public LinkGraph::ConstNode {
|
||||||
private:
|
private:
|
||||||
NodeAnnotation &node_anno; ///< Annotation being wrapped.
|
NodeAnnotation &node_anno; ///< Annotation being wrapped.
|
||||||
EdgeAnnotation *edge_annos; ///< Edge annotations belonging to this node.
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -163,21 +173,9 @@ public:
|
|||||||
*/
|
*/
|
||||||
Node (LinkGraphJob *lgj, NodeID node) :
|
Node (LinkGraphJob *lgj, NodeID node) :
|
||||||
LinkGraph::ConstNode(&lgj->link_graph, node),
|
LinkGraph::ConstNode(&lgj->link_graph, node),
|
||||||
node_anno(lgj->nodes[node]), edge_annos(lgj->edges[node])
|
node_anno(lgj->nodes[node])
|
||||||
{}
|
{}
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve an edge starting at this node. Mind that this returns an
|
|
||||||
* object, not a reference.
|
|
||||||
* @param to Remote end of the edge.
|
|
||||||
* @return Edge between this node and "to".
|
|
||||||
*/
|
|
||||||
AnnoEdge operator[](NodeID to) const { return AnnoEdge(this->edge_annos[to]); }
|
|
||||||
|
|
||||||
Edge MakeEdge(const LinkGraph::BaseEdge &base_edge, NodeID to) const { return Edge(base_edge, this->edge_annos[to]); }
|
|
||||||
|
|
||||||
Edge MakeEdge(const LinkGraphJob &lgj, NodeID to) const { return this->MakeEdge(lgj.GetBaseEdge(this->GetNodeID(), to), to); }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get amount of supply that hasn't been delivered, yet.
|
* Get amount of supply that hasn't been delivered, yet.
|
||||||
* @return Undelivered supply.
|
* @return Undelivered supply.
|
||||||
@@ -242,6 +240,21 @@ public:
|
|||||||
{
|
{
|
||||||
this->node_anno.demands = demands;
|
this->node_anno.demands = demands;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Edge &GetEdgeTo(NodeID to)
|
||||||
|
{
|
||||||
|
for (Edge &edge : this->node_anno.edges) {
|
||||||
|
if (edge.To() == to) return edge;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Edge empty_edge = {};
|
||||||
|
return empty_edge;
|
||||||
|
}
|
||||||
|
|
||||||
|
span<Edge> GetEdges()
|
||||||
|
{
|
||||||
|
return this->node_anno.edges;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -346,26 +359,6 @@ public:
|
|||||||
* @return Link graph.
|
* @return Link graph.
|
||||||
*/
|
*/
|
||||||
inline const LinkGraph &Graph() const { return this->link_graph; }
|
inline const LinkGraph &Graph() const { return this->link_graph; }
|
||||||
|
|
||||||
const LinkGraph::BaseEdge &GetBaseEdge(NodeID from, NodeID to) const
|
|
||||||
{
|
|
||||||
return this->link_graph.GetBaseEdge(from, to);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename F>
|
|
||||||
void IterateEdgesFromNode(const Node &from_node, F proc)
|
|
||||||
{
|
|
||||||
auto iter = this->link_graph.GetEdges().lower_bound(std::make_pair(from_node.GetNodeID(), (NodeID)0));
|
|
||||||
while (iter != this->link_graph.GetEdges().end()) {
|
|
||||||
NodeID from = iter->first.first;
|
|
||||||
NodeID to = iter->first.second;
|
|
||||||
if (from != from_node.GetNodeID()) return;
|
|
||||||
if (from != to) {
|
|
||||||
proc(from, to, from_node.MakeEdge(iter->second, to));
|
|
||||||
}
|
|
||||||
++iter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -471,4 +464,11 @@ protected:
|
|||||||
inline void SetParent(Path *parent) { this->parent_storage = reinterpret_cast<uintptr_t>(parent) | (this->parent_storage & 1); }
|
inline void SetParent(Path *parent) { this->parent_storage = reinterpret_cast<uintptr_t>(parent) | (this->parent_storage & 1); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline bool IsLinkGraphCargoExpress(CargoID cargo)
|
||||||
|
{
|
||||||
|
return IsCargoInClass(cargo, CC_PASSENGERS) ||
|
||||||
|
IsCargoInClass(cargo, CC_MAIL) ||
|
||||||
|
IsCargoInClass(cargo, CC_EXPRESS);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* LINKGRAPHJOB_H */
|
#endif /* LINKGRAPHJOB_H */
|
||||||
|
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
typedef LinkGraphJob::Node Node;
|
typedef LinkGraphJob::Node Node;
|
||||||
typedef LinkGraphJob::Edge Edge;
|
typedef LinkGraphJob::Edge Edge;
|
||||||
typedef LinkGraphJob::AnnoEdge AnnoEdge;
|
|
||||||
typedef LinkGraphJob::DemandAnnotation DemandAnnotation;
|
typedef LinkGraphJob::DemandAnnotation DemandAnnotation;
|
||||||
|
|
||||||
#endif /* LINKGRAPHJOB_BASE_H */
|
#endif /* LINKGRAPHJOB_BASE_H */
|
||||||
|
@@ -112,10 +112,10 @@ public:
|
|||||||
class GraphEdgeIterator {
|
class GraphEdgeIterator {
|
||||||
private:
|
private:
|
||||||
LinkGraphJob &job; ///< Job being executed
|
LinkGraphJob &job; ///< Job being executed
|
||||||
LinkGraph::EdgeMatrix::const_iterator i; ///< Iterator pointing to current edge.
|
const Edge *i; ///< Iterator pointing to current edge.
|
||||||
LinkGraph::EdgeMatrix::const_iterator end; ///< Iterator pointing beyond last edge.
|
const Edge *end; ///< Iterator pointing beyond last edge.
|
||||||
NodeID node; ///< Source node
|
NodeID node; ///< Source node
|
||||||
const LinkGraph::BaseEdge *saved; ///< Saved edge
|
const Edge *saved; ///< Saved edge
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@@ -124,7 +124,7 @@ public:
|
|||||||
* @param job Job to iterate on.
|
* @param job Job to iterate on.
|
||||||
*/
|
*/
|
||||||
GraphEdgeIterator(LinkGraphJob &job) : job(job),
|
GraphEdgeIterator(LinkGraphJob &job) : job(job),
|
||||||
i(LinkGraph::EdgeMatrix::const_iterator()), end(LinkGraph::EdgeMatrix::const_iterator()), node(INVALID_NODE), saved(nullptr)
|
i(nullptr), end(nullptr), node(INVALID_NODE), saved(nullptr)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -134,8 +134,9 @@ public:
|
|||||||
*/
|
*/
|
||||||
void SetNode(NodeID source, NodeID node)
|
void SetNode(NodeID source, NodeID node)
|
||||||
{
|
{
|
||||||
this->i = this->job.Graph().GetEdges().lower_bound(std::make_pair(node, (NodeID)0));
|
Node node_anno = this->job[node];
|
||||||
this->end = this->job.Graph().GetEdges().end();
|
this->i = node_anno.GetEdges().begin();
|
||||||
|
this->end = node_anno.GetEdges().end();
|
||||||
this->node = node;
|
this->node = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,17 +147,15 @@ public:
|
|||||||
NodeID Next()
|
NodeID Next()
|
||||||
{
|
{
|
||||||
if (this->i == this->end) return INVALID_NODE;
|
if (this->i == this->end) return INVALID_NODE;
|
||||||
NodeID from = this->i->first.first;
|
NodeID to = this->i->To();
|
||||||
NodeID to = this->i->first.second;
|
this->saved = this->i;
|
||||||
if (from != this->node) return INVALID_NODE;
|
|
||||||
this->saved = &(this->i->second);
|
|
||||||
++this->i;
|
++this->i;
|
||||||
return to;
|
return to;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SavedEdge() const { return true; }
|
bool SavedEdge() const { return true; }
|
||||||
|
|
||||||
const LinkGraph::BaseEdge &GetSavedEdge() { return *(this->saved); }
|
const Edge &GetSavedEdge() { return *(this->saved); }
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -221,7 +220,7 @@ public:
|
|||||||
|
|
||||||
bool SavedEdge() const { return false; }
|
bool SavedEdge() const { return false; }
|
||||||
|
|
||||||
const LinkGraph::BaseEdge &GetSavedEdge() { NOT_REACHED(); }
|
const Edge &GetSavedEdge() { NOT_REACHED(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -301,8 +300,6 @@ void MultiCommodityFlow::Dijkstra(NodeID source_node, PathVector &paths)
|
|||||||
|
|
||||||
this->job.path_allocator.SetParameters(sizeof(Tannotation), (8192 - 32) / sizeof(Tannotation));
|
this->job.path_allocator.SetParameters(sizeof(Tannotation), (8192 - 32) / sizeof(Tannotation));
|
||||||
|
|
||||||
const uint16 aircraft_link_scale = this->job.Settings().aircraft_link_scale;
|
|
||||||
|
|
||||||
for (NodeID node = 0; node < size; ++node) {
|
for (NodeID node = 0; node < size; ++node) {
|
||||||
Tannotation *anno = new (this->job.path_allocator.Allocate()) Tannotation(node, node == source_node);
|
Tannotation *anno = new (this->job.path_allocator.Allocate()) Tannotation(node, node == source_node);
|
||||||
anno->UpdateAnnotation();
|
anno->UpdateAnnotation();
|
||||||
@@ -320,39 +317,18 @@ void MultiCommodityFlow::Dijkstra(NodeID source_node, PathVector &paths)
|
|||||||
iter.SetNode(source_node, from);
|
iter.SetNode(source_node, from);
|
||||||
for (NodeID to = iter.Next(); to != INVALID_NODE; to = iter.Next()) {
|
for (NodeID to = iter.Next(); to != INVALID_NODE; to = iter.Next()) {
|
||||||
if (to == from) continue; // Not a real edge but a consumption sign.
|
if (to == from) continue; // Not a real edge but a consumption sign.
|
||||||
const LinkGraph::BaseEdge &base_edge = iter.SavedEdge() ? iter.GetSavedEdge() : this->job.GetBaseEdge(from, to);
|
const Edge &edge = iter.SavedEdge() ? iter.GetSavedEdge() : this->job[from].GetEdgeTo(to);
|
||||||
Edge edge = this->job[from].MakeEdge(base_edge, to);
|
|
||||||
uint capacity = edge.Capacity();
|
uint capacity = edge.Capacity();
|
||||||
if (this->max_saturation != UINT_MAX) {
|
if (this->max_saturation != UINT_MAX) {
|
||||||
capacity *= this->max_saturation;
|
capacity *= this->max_saturation;
|
||||||
capacity /= 100;
|
capacity /= 100;
|
||||||
if (capacity == 0) capacity = 1;
|
if (capacity == 0) capacity = 1;
|
||||||
}
|
}
|
||||||
/* 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. */
|
|
||||||
bool express = IsLinkGraphCargoExpress(this->job.Cargo());
|
|
||||||
|
|
||||||
auto calculate_distance = [&]() {
|
|
||||||
return DistanceMaxPlusManhattan(this->job[from].XY(), this->job[to].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;
|
|
||||||
}
|
|
||||||
Tannotation *dest = static_cast<Tannotation *>(paths[to]);
|
Tannotation *dest = static_cast<Tannotation *>(paths[to]);
|
||||||
if (dest->IsBetter(source, capacity, capacity - edge.Flow(), distance_anno)) {
|
if (dest->IsBetter(source, capacity, capacity - edge.Flow(), edge.DistanceAnno())) {
|
||||||
if (dest->GetAnnosSetFlag()) annos.erase(AnnoSetItem<Tannotation>(dest));
|
if (dest->GetAnnosSetFlag()) annos.erase(AnnoSetItem<Tannotation>(dest));
|
||||||
dest->Fork(source, capacity, capacity - edge.Flow(), distance_anno);
|
dest->Fork(source, capacity, capacity - edge.Flow(), edge.DistanceAnno());
|
||||||
dest->UpdateAnnotation();
|
dest->UpdateAnnotation();
|
||||||
annos.insert(AnnoSetItem<Tannotation>(dest));
|
annos.insert(AnnoSetItem<Tannotation>(dest));
|
||||||
dest->SetAnnosSetFlag(true);
|
dest->SetAnnosSetFlag(true);
|
||||||
@@ -447,7 +423,7 @@ void MCF1stPass::EliminateCycle(PathVector &path, Path *cycle_begin, uint flow)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
cycle_begin = path[prev];
|
cycle_begin = path[prev];
|
||||||
AnnoEdge edge = this->job[prev][cycle_begin->GetNode()];
|
Edge &edge = this->job[prev].GetEdgeTo(cycle_begin->GetNode());
|
||||||
edge.RemoveFlow(flow);
|
edge.RemoveFlow(flow);
|
||||||
} while (cycle_begin != cycle_end);
|
} while (cycle_begin != cycle_end);
|
||||||
}
|
}
|
||||||
|
@@ -89,11 +89,4 @@ public:
|
|||||||
virtual ~MCFHandler() {}
|
virtual ~MCFHandler() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline bool IsLinkGraphCargoExpress(CargoID cargo)
|
|
||||||
{
|
|
||||||
return IsCargoInClass(cargo, CC_PASSENGERS) ||
|
|
||||||
IsCargoInClass(cargo, CC_MAIL) ||
|
|
||||||
IsCargoInClass(cargo, CC_EXPRESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* MCF_H */
|
#endif /* MCF_H */
|
||||||
|
Reference in New Issue
Block a user