|
|
|
@ -28,7 +28,7 @@ extern LinkGraphJobPool _link_graph_job_pool;
|
|
|
|
|
* Class for calculation jobs to be run on link graphs.
|
|
|
|
|
*/
|
|
|
|
|
class LinkGraphJob : public LinkGraphJobPool::PoolItem<&_link_graph_job_pool>{
|
|
|
|
|
private:
|
|
|
|
|
public:
|
|
|
|
|
/**
|
|
|
|
|
* Demand between two nodes.
|
|
|
|
|
*/
|
|
|
|
@ -41,74 +41,23 @@ private:
|
|
|
|
|
* Annotation for a link graph edge.
|
|
|
|
|
*/
|
|
|
|
|
struct EdgeAnnotation {
|
|
|
|
|
uint flow; ///< Planned flow over this edge.
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Annotation for a link graph node.
|
|
|
|
|
*/
|
|
|
|
|
struct NodeAnnotation {
|
|
|
|
|
uint undelivered_supply; ///< Amount of supply that hasn't been distributed yet.
|
|
|
|
|
PathList paths; ///< Paths through this node, sorted so that those with flow == 0 are in the back.
|
|
|
|
|
FlowStatMap flows; ///< Planned flows to other nodes.
|
|
|
|
|
|
|
|
|
|
std::vector<EdgeAnnotation> edges; ///< Annotations for all edges originating at this node.
|
|
|
|
|
std::vector<DemandAnnotation> demands; ///< Annotations for the demand to all other nodes.
|
|
|
|
|
|
|
|
|
|
NodeAnnotation(const LinkGraph::BaseNode &node, size_t size) : undelivered_supply(node.supply), paths(), flows()
|
|
|
|
|
{
|
|
|
|
|
this->edges.resize(node.edges.size());
|
|
|
|
|
this->demands.resize(size);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
typedef std::vector<NodeAnnotation> NodeAnnotationVector;
|
|
|
|
|
|
|
|
|
|
friend SaveLoadTable GetLinkGraphJobDesc();
|
|
|
|
|
friend class LinkGraphSchedule;
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
const LinkGraph link_graph; ///< Link graph to by analyzed. Is copied when job is started and mustn't be modified later.
|
|
|
|
|
const LinkGraphSettings settings; ///< Copy of _settings_game.linkgraph at spawn time.
|
|
|
|
|
std::thread thread; ///< Thread the job is running in or a default-constructed thread if it's running in the main thread.
|
|
|
|
|
Date join_date; ///< Date when the job is to be joined.
|
|
|
|
|
NodeAnnotationVector nodes; ///< Extra node 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_aborted; ///< Has the job been aborted. This is accessed by multiple threads and reads may be stale.
|
|
|
|
|
|
|
|
|
|
void EraseFlows(NodeID from);
|
|
|
|
|
void JoinThread();
|
|
|
|
|
void SpawnThread();
|
|
|
|
|
const LinkGraph::BaseEdge &base; ///< Reference to the edge that is annotated.
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
uint flow; ///< Planned flow over this edge.
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 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 {
|
|
|
|
|
private:
|
|
|
|
|
EdgeAnnotation &anno; ///< Annotation being wrapped.
|
|
|
|
|
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), anno(anno) {}
|
|
|
|
|
EdgeAnnotation(const LinkGraph::BaseEdge &base) : base(base), flow(0) {}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the total flow on the edge.
|
|
|
|
|
* @return Flow.
|
|
|
|
|
*/
|
|
|
|
|
uint Flow() const { return this->anno.flow; }
|
|
|
|
|
uint Flow() const { return this->flow; }
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Add some flow.
|
|
|
|
|
* @param flow Flow to be added.
|
|
|
|
|
*/
|
|
|
|
|
void AddFlow(uint flow) { this->anno.flow += flow; }
|
|
|
|
|
void AddFlow(uint flow) { this->flow += flow; }
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Remove some flow.
|
|
|
|
@ -116,140 +65,71 @@ public:
|
|
|
|
|
*/
|
|
|
|
|
void RemoveFlow(uint flow)
|
|
|
|
|
{
|
|
|
|
|
assert(flow <= this->anno.flow);
|
|
|
|
|
this->anno.flow -= flow;
|
|
|
|
|
assert(flow <= this->flow);
|
|
|
|
|
this->flow -= flow;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
friend inline bool operator <(NodeID dest, const EdgeAnnotation &rhs)
|
|
|
|
|
{
|
|
|
|
|
return dest < rhs.base.dest_node;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Iterator for job edges.
|
|
|
|
|
* Annotation for a link graph node.
|
|
|
|
|
*/
|
|
|
|
|
class EdgeIterator : public LinkGraph::BaseEdgeIterator<const LinkGraph::BaseEdge, Edge, EdgeIterator> {
|
|
|
|
|
span<EdgeAnnotation> base_anno; ///< Array of annotations to be (indirectly) iterated.
|
|
|
|
|
public:
|
|
|
|
|
/**
|
|
|
|
|
* Constructor.
|
|
|
|
|
* @param base Array of edges to be iterated.
|
|
|
|
|
* @param base_anno Array of annotations to be iterated.
|
|
|
|
|
* @param current Start offset of iteration.
|
|
|
|
|
*/
|
|
|
|
|
EdgeIterator(span<const LinkGraph::BaseEdge> base, span<EdgeAnnotation> base_anno, bool end) :
|
|
|
|
|
LinkGraph::BaseEdgeIterator<const LinkGraph::BaseEdge, Edge, EdgeIterator>(base, end),
|
|
|
|
|
base_anno(base_anno) {}
|
|
|
|
|
struct NodeAnnotation {
|
|
|
|
|
const LinkGraph::BaseNode &base; ///< Reference to the node that is annotated.
|
|
|
|
|
|
|
|
|
|
EdgeIterator() :
|
|
|
|
|
LinkGraph::BaseEdgeIterator<const LinkGraph::BaseEdge, Edge, EdgeIterator>(span<const LinkGraph::BaseEdge>(), true),
|
|
|
|
|
base_anno() {}
|
|
|
|
|
uint undelivered_supply; ///< Amount of supply that hasn't been distributed yet.
|
|
|
|
|
PathList paths; ///< Paths through this node, sorted so that those with flow == 0 are in the back.
|
|
|
|
|
FlowStatMap flows; ///< Planned flows to other nodes.
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Dereference.
|
|
|
|
|
* @return Pair of the edge currently pointed to and the ID of its
|
|
|
|
|
* other end.
|
|
|
|
|
*/
|
|
|
|
|
std::pair<NodeID, Edge> operator*() const
|
|
|
|
|
std::vector<EdgeAnnotation> edges; ///< Annotations for all edges originating at this node.
|
|
|
|
|
std::vector<DemandAnnotation> demands; ///< Annotations for the demand to all other nodes.
|
|
|
|
|
|
|
|
|
|
NodeAnnotation(const LinkGraph::BaseNode &node, size_t size) : base(node), undelivered_supply(node.supply), paths(), flows()
|
|
|
|
|
{
|
|
|
|
|
return std::pair<NodeID, Edge>(this->base[this->current].dest_node, Edge(this->base[this->current], this->base_anno[this->current]));
|
|
|
|
|
this->edges.reserve(node.edges.size());
|
|
|
|
|
for (auto &e : node.edges) this->edges.emplace_back(e);
|
|
|
|
|
this->demands.resize(size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Dereference. Has to be repeated here as operator* is different than
|
|
|
|
|
* in LinkGraph::EdgeWrapper.
|
|
|
|
|
* @return Fake pointer to pair of NodeID/Edge.
|
|
|
|
|
* Retrieve an edge starting at this node.
|
|
|
|
|
* @param to Remote end of the edge.
|
|
|
|
|
* @return Edge between this node and "to".
|
|
|
|
|
*/
|
|
|
|
|
FakePointer operator->() const {
|
|
|
|
|
return FakePointer(this->operator*());
|
|
|
|
|
EdgeAnnotation &operator[](NodeID to)
|
|
|
|
|
{
|
|
|
|
|
auto it = std::find_if(this->edges.begin(), this->edges.end(), [=] (const EdgeAnnotation &e) { return e.base.dest_node == to; });
|
|
|
|
|
assert(it != this->edges.end());
|
|
|
|
|
return *it;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Link graph job node. Wraps a constant link graph node and a modifiable
|
|
|
|
|
* node annotation.
|
|
|
|
|
*/
|
|
|
|
|
class Node : public LinkGraph::ConstNode {
|
|
|
|
|
private:
|
|
|
|
|
NodeAnnotation &node_anno; ///< Annotation being wrapped.
|
|
|
|
|
span<EdgeAnnotation> edge_annos; ///< Edge annotations belonging to this node.
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Constructor.
|
|
|
|
|
* @param lgj Job to take the node from.
|
|
|
|
|
* @param node ID of the node.
|
|
|
|
|
*/
|
|
|
|
|
Node (LinkGraphJob *lgj, NodeID node) :
|
|
|
|
|
LinkGraph::ConstNode(&lgj->link_graph, node),
|
|
|
|
|
node_anno(lgj->nodes[node]), edge_annos(lgj->nodes[node].edges)
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Retrieve an edge starting at this node. Mind that this returns an
|
|
|
|
|
* object, not a reference.
|
|
|
|
|
* Retrieve an edge starting at this node.
|
|
|
|
|
* @param to Remote end of the edge.
|
|
|
|
|
* @return Edge between this node and "to".
|
|
|
|
|
*/
|
|
|
|
|
Edge operator[](NodeID to) const
|
|
|
|
|
const EdgeAnnotation &operator[](NodeID to) const
|
|
|
|
|
{
|
|
|
|
|
assert(this->HasEdgeTo(to));
|
|
|
|
|
auto index = std::distance(this->node.edges.begin(), this->GetEdge(to));
|
|
|
|
|
return Edge(this->node.edges[index], this->edge_annos[index]);
|
|
|
|
|
auto it = std::find_if(this->edges.begin(), this->edges.end(), [=] (const EdgeAnnotation &e) { return e.base.dest_node == to; });
|
|
|
|
|
assert(it != this->edges.end());
|
|
|
|
|
return *it;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Iterator for the "begin" of the edge array. Only edges with capacity
|
|
|
|
|
* are iterated. The others are skipped.
|
|
|
|
|
* @return Iterator pointing to the first edge.
|
|
|
|
|
*/
|
|
|
|
|
EdgeIterator Begin() const { return EdgeIterator(this->node.edges, this->edge_annos, false); }
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Iterator for the "end" of the edge array. Only edges with capacity
|
|
|
|
|
* are iterated. The others are skipped.
|
|
|
|
|
* @return Iterator pointing beyond the last edge.
|
|
|
|
|
*/
|
|
|
|
|
EdgeIterator End() const { return EdgeIterator(this->node.edges, this->edge_annos, true); }
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get amount of supply that hasn't been delivered, yet.
|
|
|
|
|
* @return Undelivered supply.
|
|
|
|
|
*/
|
|
|
|
|
uint UndeliveredSupply() const { return this->node_anno.undelivered_supply; }
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the flows running through this node.
|
|
|
|
|
* @return Flows.
|
|
|
|
|
*/
|
|
|
|
|
FlowStatMap &Flows() { return this->node_anno.flows; }
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get a constant version of the flows running through this node.
|
|
|
|
|
* @return Flows.
|
|
|
|
|
*/
|
|
|
|
|
const FlowStatMap &Flows() const { return this->node_anno.flows; }
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the paths this node is part of. Paths are always expected to be
|
|
|
|
|
* sorted so that those with flow == 0 are in the back of the list.
|
|
|
|
|
* @return Paths.
|
|
|
|
|
*/
|
|
|
|
|
PathList &Paths() { return this->node_anno.paths; }
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get a constant version of the paths this node is part of.
|
|
|
|
|
* @return Paths.
|
|
|
|
|
*/
|
|
|
|
|
const PathList &Paths() const { return this->node_anno.paths; }
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the transport demand between end the points of the edge.
|
|
|
|
|
* @return Demand.
|
|
|
|
|
*/
|
|
|
|
|
uint DemandTo(NodeID to) const { return this->node_anno.demands[to].demand; }
|
|
|
|
|
uint DemandTo(NodeID to) const { return this->demands[to].demand; }
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the transport demand that hasn't been satisfied by flows, yet.
|
|
|
|
|
* @return Unsatisfied demand.
|
|
|
|
|
*/
|
|
|
|
|
uint UnsatisfiedDemandTo(NodeID to) const { return this->node_anno.demands[to].unsatisfied_demand; }
|
|
|
|
|
uint UnsatisfiedDemandTo(NodeID to) const { return this->demands[to].unsatisfied_demand; }
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Satisfy some demand.
|
|
|
|
@ -257,8 +137,8 @@ public:
|
|
|
|
|
*/
|
|
|
|
|
void SatisfyDemandTo(NodeID to, uint demand)
|
|
|
|
|
{
|
|
|
|
|
assert(demand <= this->node_anno.demands[to].unsatisfied_demand);
|
|
|
|
|
this->node_anno.demands[to].unsatisfied_demand -= demand;
|
|
|
|
|
assert(demand <= this->demands[to].unsatisfied_demand);
|
|
|
|
|
this->demands[to].unsatisfied_demand -= demand;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -268,12 +148,32 @@ public:
|
|
|
|
|
*/
|
|
|
|
|
void DeliverSupply(NodeID to, uint amount)
|
|
|
|
|
{
|
|
|
|
|
this->node_anno.undelivered_supply -= amount;
|
|
|
|
|
this->node_anno.demands[to].demand += amount;
|
|
|
|
|
this->node_anno.demands[to].unsatisfied_demand += amount;
|
|
|
|
|
this->undelivered_supply -= amount;
|
|
|
|
|
this->demands[to].demand += amount;
|
|
|
|
|
this->demands[to].unsatisfied_demand += amount;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
typedef std::vector<NodeAnnotation> NodeAnnotationVector;
|
|
|
|
|
|
|
|
|
|
friend SaveLoadTable GetLinkGraphJobDesc();
|
|
|
|
|
friend class LinkGraphSchedule;
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
const LinkGraph link_graph; ///< Link graph to by analyzed. Is copied when job is started and mustn't be modified later.
|
|
|
|
|
const LinkGraphSettings settings; ///< Copy of _settings_game.linkgraph at spawn time.
|
|
|
|
|
std::thread thread; ///< Thread the job is running in or a default-constructed thread if it's running in the main thread.
|
|
|
|
|
Date join_date; ///< Date when the job is to be joined.
|
|
|
|
|
NodeAnnotationVector nodes; ///< Extra node 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_aborted; ///< Has the job been aborted. This is accessed by multiple threads and reads may be stale.
|
|
|
|
|
|
|
|
|
|
void EraseFlows(NodeID from);
|
|
|
|
|
void JoinThread();
|
|
|
|
|
void SpawnThread();
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
/**
|
|
|
|
|
* Bare constructor, only for save/load. link_graph, join_date and actually
|
|
|
|
|
* settings have to be brutally const-casted in order to populate them.
|
|
|
|
@ -337,7 +237,7 @@ public:
|
|
|
|
|
* @param num ID of the node.
|
|
|
|
|
* @return the Requested node.
|
|
|
|
|
*/
|
|
|
|
|
inline Node operator[](NodeID num) { return Node(this, num); }
|
|
|
|
|
inline NodeAnnotation &operator[](NodeID num) { return this->nodes[num]; }
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the size of the underlying link graph.
|
|
|
|
|