diff --git a/src/linkgraph/linkgraphjob.cpp b/src/linkgraph/linkgraphjob.cpp index d5304ca56e..047bfc7f67 100644 --- a/src/linkgraph/linkgraphjob.cpp +++ b/src/linkgraph/linkgraphjob.cpp @@ -182,7 +182,7 @@ void LinkGraphJob::Init() uint size = this->Size(); this->nodes.reserve(size); 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()); } } diff --git a/src/linkgraph/linkgraphjob.h b/src/linkgraph/linkgraphjob.h index 9bcc59da7e..265131ef24 100644 --- a/src/linkgraph/linkgraphjob.h +++ b/src/linkgraph/linkgraphjob.h @@ -30,11 +30,17 @@ extern LinkGraphJobPool _link_graph_job_pool; class LinkGraphJob : public LinkGraphJobPool::PoolItem<&_link_graph_job_pool>{ private: /** - * Annotation for a link graph edge. + * Demand between two nodes. */ - struct EdgeAnnotation { + struct DemandAnnotation { uint demand; ///< Transport demand between the nodes. 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. }; @@ -46,11 +52,13 @@ private: 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 edges; + std::vector edges; ///< Annotations for all edges originating at this node. + std::vector 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->demands.resize(size); } }; @@ -90,18 +98,6 @@ public: Edge(const LinkGraph::BaseEdge &edge, EdgeAnnotation &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. * @return Flow. @@ -123,26 +119,6 @@ public: assert(flow <= this->anno.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; } + /** + * 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. * @param to Destination for supply. @@ -266,7 +264,8 @@ public: void DeliverSupply(NodeID to, uint 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; } }; diff --git a/src/linkgraph/mcf.cpp b/src/linkgraph/mcf.cpp index 78ca36eeed..599bac3d52 100644 --- a/src/linkgraph/mcf.cpp +++ b/src/linkgraph/mcf.cpp @@ -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 * 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 accuracy Accuracy of the calculation. * @param max_saturation If < UINT_MAX only push flow up to the given * 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) { - assert(edge.UnsatisfiedDemand() > 0); - uint flow = Clamp(edge.Demand() / accuracy, 1, edge.UnsatisfiedDemand()); + assert(node.UnsatisfiedDemandTo(to) > 0); + uint flow = Clamp(node.DemandTo(to) / accuracy, 1, node.UnsatisfiedDemandTo(to)); flow = path->AddFlow(flow, this->job, max_saturation); - edge.SatisfyDemand(flow); + node.SatisfyDemandTo(to, flow); return flow; } @@ -511,25 +512,25 @@ MCF1stPass::MCF1stPass(LinkGraphJob &job) : MultiCommodityFlow(job) /* First saturate the shortest paths. */ this->Dijkstra(source, paths); + Node src_node = job[source]; bool source_demand_left = false; for (NodeID dest = 0; dest < size; ++dest) { - Edge edge = job[source][dest]; - if (edge.UnsatisfiedDemand() > 0) { + if (src_node.UnsatisfiedDemandTo(dest) > 0) { Path *path = paths[dest]; assert(path != nullptr); /* Generally only allow paths that don't exceed the * available capacity. But if no demand has been assigned * 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) { /* If a path has been found there is a chance we can * find more. */ - more_loops = more_loops || (edge.UnsatisfiedDemand() > 0); - } else if (edge.UnsatisfiedDemand() == edge.Demand() && + more_loops = more_loops || (src_node.UnsatisfiedDemandTo(dest) > 0); + } else if (src_node.UnsatisfiedDemandTo(dest) == src_node.DemandTo(dest) && 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; @@ -558,13 +559,13 @@ MCF2ndPass::MCF2ndPass(LinkGraphJob &job) : MultiCommodityFlow(job) this->Dijkstra(source, paths); + Node src_node = job[source]; bool source_demand_left = false; for (NodeID dest = 0; dest < size; ++dest) { - Edge edge = this->job[source][dest]; Path *path = paths[dest]; - if (edge.UnsatisfiedDemand() > 0 && path->GetFreeCapacity() > INT_MIN) { - this->PushFlow(edge, path, accuracy, UINT_MAX); - if (edge.UnsatisfiedDemand() > 0) { + if (src_node.UnsatisfiedDemandTo(dest) > 0 && path->GetFreeCapacity() > INT_MIN) { + this->PushFlow(src_node, dest, path, accuracy, UINT_MAX); + if (src_node.UnsatisfiedDemandTo(dest) > 0) { demand_left = true; source_demand_left = true; } diff --git a/src/linkgraph/mcf.h b/src/linkgraph/mcf.h index 4ad598c574..e1e83e3898 100644 --- a/src/linkgraph/mcf.h +++ b/src/linkgraph/mcf.h @@ -24,7 +24,7 @@ protected: template 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);