Codechange: [Linkgraph] Split annotation for demand between nodes from the edge annotations.

pull/491/head
Michael Lutz 2 years ago
parent 564de01d66
commit 8f851ead70

@ -182,7 +182,7 @@ void LinkGraphJob::Init()
uint size = this->Size(); uint size = this->Size();
this->nodes.reserve(size); this->nodes.reserve(size);
for (uint i = 0; i < size; ++i) { for (uint i = 0; i < size; ++i) {
this->nodes.emplace_back(this->link_graph.nodes[i]); this->nodes.emplace_back(this->link_graph.nodes[i], this->link_graph.Size());
} }
} }

@ -30,11 +30,17 @@ extern LinkGraphJobPool _link_graph_job_pool;
class LinkGraphJob : public LinkGraphJobPool::PoolItem<&_link_graph_job_pool>{ class LinkGraphJob : public LinkGraphJobPool::PoolItem<&_link_graph_job_pool>{
private: private:
/** /**
* Annotation for a link graph edge. * Demand between two nodes.
*/ */
struct EdgeAnnotation { struct DemandAnnotation {
uint demand; ///< Transport demand between the nodes. uint demand; ///< Transport demand between the nodes.
uint unsatisfied_demand; ///< Demand over this edge that hasn't been satisfied yet. uint unsatisfied_demand; ///< Demand over this edge that hasn't been satisfied yet.
};
/**
* Annotation for a link graph edge.
*/
struct EdgeAnnotation {
uint flow; ///< Planned flow over this edge. uint flow; ///< Planned flow over this edge.
}; };
@ -46,11 +52,13 @@ 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.
std::vector<EdgeAnnotation> edges; 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) : undelivered_supply(node.supply), paths(), flows() NodeAnnotation(const LinkGraph::BaseNode &node, size_t size) : undelivered_supply(node.supply), paths(), flows()
{ {
this->edges.resize(node.edges.size()); this->edges.resize(node.edges.size());
this->demands.resize(size);
} }
}; };
@ -90,18 +98,6 @@ public:
Edge(const LinkGraph::BaseEdge &edge, EdgeAnnotation &anno) : Edge(const LinkGraph::BaseEdge &edge, EdgeAnnotation &anno) :
LinkGraph::ConstEdge(edge), anno(anno) {} LinkGraph::ConstEdge(edge), anno(anno) {}
/**
* Get the transport demand between end the points of the edge.
* @return Demand.
*/
uint Demand() const { return this->anno.demand; }
/**
* Get the transport demand that hasn't been satisfied by flows, yet.
* @return Unsatisfied demand.
*/
uint UnsatisfiedDemand() const { return this->anno.unsatisfied_demand; }
/** /**
* Get the total flow on the edge. * Get the total flow on the edge.
* @return Flow. * @return Flow.
@ -123,26 +119,6 @@ public:
assert(flow <= this->anno.flow); assert(flow <= this->anno.flow);
this->anno.flow -= flow; this->anno.flow -= flow;
} }
/**
* Add some (not yet satisfied) demand.
* @param demand Demand to be added.
*/
void AddDemand(uint demand)
{
this->anno.demand += demand;
this->anno.unsatisfied_demand += demand;
}
/**
* Satisfy some demand.
* @param demand Demand to be satisfied.
*/
void SatisfyDemand(uint demand)
{
assert(demand <= this->anno.unsatisfied_demand);
this->anno.unsatisfied_demand -= demand;
}
}; };
/** /**
@ -258,6 +234,28 @@ public:
*/ */
const PathList &Paths() const { return this->node_anno.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; }
/**
* 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; }
/**
* Satisfy some demand.
* @param demand Demand to be satisfied.
*/
void SatisfyDemandTo(NodeID to, uint demand)
{
assert(demand <= this->node_anno.demands[to].unsatisfied_demand);
this->node_anno.demands[to].unsatisfied_demand -= demand;
}
/** /**
* Deliver some supply, adding demand to the respective edge. * Deliver some supply, adding demand to the respective edge.
* @param to Destination for supply. * @param to Destination for supply.
@ -266,7 +264,8 @@ public:
void DeliverSupply(NodeID to, uint amount) void DeliverSupply(NodeID to, uint amount)
{ {
this->node_anno.undelivered_supply -= amount; this->node_anno.undelivered_supply -= amount;
(*this)[to].AddDemand(amount); this->node_anno.demands[to].demand += amount;
this->node_anno.demands[to].unsatisfied_demand += amount;
} }
}; };

@ -334,19 +334,20 @@ void MultiCommodityFlow::CleanupPaths(NodeID source_id, PathVector &paths)
/** /**
* Push flow along a path and update the unsatisfied_demand of the associated * Push flow along a path and update the unsatisfied_demand of the associated
* edge. * edge.
* @param edge Edge whose ends the path connects. * @param node Node where the path starts.
* @param to Node where the path ends.
* @param path End of the path the flow should be pushed on. * @param path End of the path the flow should be pushed on.
* @param accuracy Accuracy of the calculation. * @param accuracy Accuracy of the calculation.
* @param max_saturation If < UINT_MAX only push flow up to the given * @param max_saturation If < UINT_MAX only push flow up to the given
* saturation, otherwise the path can be "overloaded". * saturation, otherwise the path can be "overloaded".
*/ */
uint MultiCommodityFlow::PushFlow(Edge &edge, Path *path, uint accuracy, uint MultiCommodityFlow::PushFlow(Node &node, NodeID to, Path *path, uint accuracy,
uint max_saturation) uint max_saturation)
{ {
assert(edge.UnsatisfiedDemand() > 0); assert(node.UnsatisfiedDemandTo(to) > 0);
uint flow = Clamp(edge.Demand() / accuracy, 1, edge.UnsatisfiedDemand()); uint flow = Clamp(node.DemandTo(to) / accuracy, 1, node.UnsatisfiedDemandTo(to));
flow = path->AddFlow(flow, this->job, max_saturation); flow = path->AddFlow(flow, this->job, max_saturation);
edge.SatisfyDemand(flow); node.SatisfyDemandTo(to, flow);
return flow; return flow;
} }
@ -511,25 +512,25 @@ MCF1stPass::MCF1stPass(LinkGraphJob &job) : MultiCommodityFlow(job)
/* First saturate the shortest paths. */ /* First saturate the shortest paths. */
this->Dijkstra<DistanceAnnotation, GraphEdgeIterator>(source, paths); this->Dijkstra<DistanceAnnotation, GraphEdgeIterator>(source, paths);
Node src_node = job[source];
bool source_demand_left = false; bool source_demand_left = false;
for (NodeID dest = 0; dest < size; ++dest) { for (NodeID dest = 0; dest < size; ++dest) {
Edge edge = job[source][dest]; if (src_node.UnsatisfiedDemandTo(dest) > 0) {
if (edge.UnsatisfiedDemand() > 0) {
Path *path = paths[dest]; Path *path = paths[dest];
assert(path != nullptr); assert(path != nullptr);
/* Generally only allow paths that don't exceed the /* Generally only allow paths that don't exceed the
* available capacity. But if no demand has been assigned * available capacity. But if no demand has been assigned
* yet, make an exception and allow any valid path *once*. */ * yet, make an exception and allow any valid path *once*. */
if (path->GetFreeCapacity() > 0 && this->PushFlow(edge, path, if (path->GetFreeCapacity() > 0 && this->PushFlow(src_node, dest, path,
accuracy, this->max_saturation) > 0) { accuracy, this->max_saturation) > 0) {
/* If a path has been found there is a chance we can /* If a path has been found there is a chance we can
* find more. */ * find more. */
more_loops = more_loops || (edge.UnsatisfiedDemand() > 0); more_loops = more_loops || (src_node.UnsatisfiedDemandTo(dest) > 0);
} else if (edge.UnsatisfiedDemand() == edge.Demand() && } else if (src_node.UnsatisfiedDemandTo(dest) == src_node.DemandTo(dest) &&
path->GetFreeCapacity() > INT_MIN) { path->GetFreeCapacity() > INT_MIN) {
this->PushFlow(edge, path, accuracy, UINT_MAX); this->PushFlow(src_node, dest, path, accuracy, UINT_MAX);
} }
if (edge.UnsatisfiedDemand() > 0) source_demand_left = true; if (src_node.UnsatisfiedDemandTo(dest) > 0) source_demand_left = true;
} }
} }
finished_sources[source] = !source_demand_left; finished_sources[source] = !source_demand_left;
@ -558,13 +559,13 @@ MCF2ndPass::MCF2ndPass(LinkGraphJob &job) : MultiCommodityFlow(job)
this->Dijkstra<CapacityAnnotation, FlowEdgeIterator>(source, paths); this->Dijkstra<CapacityAnnotation, FlowEdgeIterator>(source, paths);
Node src_node = job[source];
bool source_demand_left = false; bool source_demand_left = false;
for (NodeID dest = 0; dest < size; ++dest) { for (NodeID dest = 0; dest < size; ++dest) {
Edge edge = this->job[source][dest];
Path *path = paths[dest]; Path *path = paths[dest];
if (edge.UnsatisfiedDemand() > 0 && path->GetFreeCapacity() > INT_MIN) { if (src_node.UnsatisfiedDemandTo(dest) > 0 && path->GetFreeCapacity() > INT_MIN) {
this->PushFlow(edge, path, accuracy, UINT_MAX); this->PushFlow(src_node, dest, path, accuracy, UINT_MAX);
if (edge.UnsatisfiedDemand() > 0) { if (src_node.UnsatisfiedDemandTo(dest) > 0) {
demand_left = true; demand_left = true;
source_demand_left = true; source_demand_left = true;
} }

@ -24,7 +24,7 @@ protected:
template<class Tannotation, class Tedge_iterator> template<class Tannotation, class Tedge_iterator>
void Dijkstra(NodeID from, PathVector &paths); void Dijkstra(NodeID from, PathVector &paths);
uint PushFlow(Edge &edge, Path *path, uint accuracy, uint max_saturation); uint PushFlow(Node &node, NodeID to, Path *path, uint accuracy, uint max_saturation);
void CleanupPaths(NodeID source, PathVector &paths); void CleanupPaths(NodeID source, PathVector &paths);

Loading…
Cancel
Save