Linkgraph: Fix demand allocation in partitioned graphs

This commit is contained in:
Jonathan G Rennison
2020-01-25 12:34:20 +00:00
parent 5b83e5ff78
commit 32284e6449
2 changed files with 67 additions and 20 deletions

View File

@@ -250,10 +250,11 @@ inline void Scaler::SetDemands(LinkGraphJob &job, NodeID from_id, NodeID to_id,
/** /**
* Do the actual demand calculation, called from constructor. * Do the actual demand calculation, called from constructor.
* @param job Job to calculate the demands for. * @param job Job to calculate the demands for.
* @param reachable_nodes Bitmap of reachable nodes.
* @tparam Tscaler Scaler to be used for scaling demands. * @tparam Tscaler Scaler to be used for scaling demands.
*/ */
template<class Tscaler> template<class Tscaler>
void DemandCalculator::CalcDemand(LinkGraphJob &job, Tscaler scaler) void DemandCalculator::CalcDemand(LinkGraphJob &job, const std::vector<bool> &reachable_nodes, Tscaler scaler)
{ {
NodeList supplies; NodeList supplies;
NodeList demands; NodeList demands;
@@ -261,6 +262,7 @@ void DemandCalculator::CalcDemand(LinkGraphJob &job, Tscaler scaler)
uint num_demands = 0; uint num_demands = 0;
for (NodeID node = 0; node < job.Size(); node++) { for (NodeID node = 0; node < job.Size(); node++) {
if (!reachable_nodes[node]) continue;
scaler.AddNode(job[node]); scaler.AddNode(job[node]);
if (job[node].Supply() > 0) { if (job[node].Supply() > 0) {
supplies.push(node); supplies.push(node);
@@ -347,15 +349,17 @@ void DemandCalculator::CalcDemand(LinkGraphJob &job, Tscaler scaler)
/** /**
* Do the actual demand calculation, called from constructor. * Do the actual demand calculation, called from constructor.
* @param job Job to calculate the demands for. * @param job Job to calculate the demands for.
* @param reachable_nodes Bitmap of reachable nodes.
* @tparam Tscaler Scaler to be used for scaling demands. * @tparam Tscaler Scaler to be used for scaling demands.
*/ */
template<class Tscaler> template<class Tscaler>
void DemandCalculator::CalcMinimisedDistanceDemand(LinkGraphJob &job, Tscaler scaler) void DemandCalculator::CalcMinimisedDistanceDemand(LinkGraphJob &job, const std::vector<bool> &reachable_nodes, Tscaler scaler)
{ {
std::vector<NodeID> supplies; std::vector<NodeID> supplies;
std::vector<NodeID> demands; std::vector<NodeID> demands;
for (NodeID node = 0; node < job.Size(); node++) { for (NodeID node = 0; node < job.Size(); node++) {
if (!reachable_nodes[node]) continue;
scaler.AddNode(job[node]); scaler.AddNode(job[node]);
if (job[node].Supply() > 0) { if (job[node].Supply() > 0) {
supplies.push_back(node); supplies.push_back(node);
@@ -413,21 +417,64 @@ DemandCalculator::DemandCalculator(LinkGraphJob &job) :
this->mod_dist = 100 + over100 * over100; this->mod_dist = 100 + over100 * over100;
} }
switch (settings.GetDistributionType(cargo)) { const uint size = job.Size();
case DT_SYMMETRIC:
this->CalcDemand<SymmetricScaler>(job, SymmetricScaler(settings.demand_size)); /* Symmetric edge matrix
break; * Storage order: e01 e02 e12 e03 e13 e23 e04 e14 e24 e34 ... */
case DT_ASYMMETRIC: auto se_index = [](uint i, uint j) -> uint {
this->CalcDemand<AsymmetricScaler>(job, AsymmetricScaler()); if (j < i) std::swap(i, j);
break; return i + (j * (j - 1) / 2);
case DT_ASYMMETRIC_EQ: };
this->CalcMinimisedDistanceDemand<AsymmetricScalerEq>(job, AsymmetricScalerEq()); std::vector<bool> symmetric_edges(se_index(0, size));
break;
case DT_ASYMMETRIC_NEAR: for (NodeID node_id = 0; node_id < size; ++node_id) {
this->CalcMinimisedDistanceDemand<AsymmetricScaler>(job, AsymmetricScaler()); Node from = job[node_id];
break; for (EdgeIterator it(from.Begin()); it != from.End(); ++it) {
default: symmetric_edges[se_index(node_id, it->first)] = true;
/* Nothing to do. */ }
break;
} }
uint first_unseen = 0;
std::vector<bool> reachable_nodes(size);
do {
reachable_nodes.assign(size, false);
std::vector<NodeID> queue;
queue.push_back(first_unseen);
reachable_nodes[first_unseen] = true;
while (!queue.empty()) {
NodeID from = queue.back();
queue.pop_back();
for (NodeID to = 0; to < size; ++to) {
if (from == to) continue;
if (symmetric_edges[se_index(from, to)]) {
std::vector<bool>::reference bit = reachable_nodes[to];
if (!bit) {
bit = true;
queue.push_back(to);
}
}
}
}
switch (settings.GetDistributionType(cargo)) {
case DT_SYMMETRIC:
this->CalcDemand<SymmetricScaler>(job, reachable_nodes, SymmetricScaler(settings.demand_size));
break;
case DT_ASYMMETRIC:
this->CalcDemand<AsymmetricScaler>(job, reachable_nodes, AsymmetricScaler());
break;
case DT_ASYMMETRIC_EQ:
this->CalcMinimisedDistanceDemand<AsymmetricScalerEq>(job, reachable_nodes, AsymmetricScalerEq());
break;
case DT_ASYMMETRIC_NEAR:
this->CalcMinimisedDistanceDemand<AsymmetricScaler>(job, reachable_nodes, AsymmetricScaler());
break;
default:
/* Nothing to do. */
break;
}
while (first_unseen < size && reachable_nodes[first_unseen]) {
first_unseen++;
}
} while (first_unseen < size);
} }

View File

@@ -19,10 +19,10 @@ private:
int32 accuracy; ///< Accuracy of the calculation. int32 accuracy; ///< Accuracy of the calculation.
template<class Tscaler> template<class Tscaler>
void CalcDemand(LinkGraphJob &job, Tscaler scaler); void CalcDemand(LinkGraphJob &job, const std::vector<bool> &reachable_nodes, Tscaler scaler);
template<class Tscaler> template<class Tscaler>
void CalcMinimisedDistanceDemand(LinkGraphJob &job, Tscaler scaler); void CalcMinimisedDistanceDemand(LinkGraphJob &job, const std::vector<bool> &reachable_nodes, Tscaler scaler);
}; };
/** /**