use super::error::AssignmentError;
use super::indexed_graph::IndexedGraph;
use crate::gmns::meso::network::Network;
use crate::log_additional;
use crate::log_main;
use crate::od::OdMatrix;
use crate::verbose::{EVENT_ASSIGNMENT, EVENT_ASSIGNMENT_ITERATION, EVENT_CONVERGENCE};
use super::{AssignmentConfig, AssignmentMethod, AssignmentResult, VolumeDelayFunction};
#[derive(Debug)]
pub struct Msa;
impl Msa {
pub fn new() -> Self {
Msa
}
}
impl Default for Msa {
fn default() -> Self {
Self::new()
}
}
impl AssignmentMethod for Msa {
fn assign(
&self,
_network: &Network,
graph: &IndexedGraph,
od_matrix: &dyn OdMatrix,
vdf: &dyn VolumeDelayFunction,
config: &AssignmentConfig,
) -> Result<AssignmentResult, AssignmentError> {
log_main!(EVENT_ASSIGNMENT, "Starting MSA assignment",);
let n = graph.num_links;
let mut costs = vec![0.0; n];
let mut volumes = vec![0.0; n];
let mut aux_volumes = vec![0.0; n];
graph.compute_costs(&volumes, vdf, &mut costs);
graph.all_or_nothing(od_matrix, &costs, &mut volumes);
let mut converged = false;
let mut relative_gap = f64::MAX;
let mut iteration = 0;
for iter in 0..config.max_iterations {
iteration = iter + 1;
graph.compute_costs(&volumes, vdf, &mut costs);
graph.all_or_nothing(od_matrix, &costs, &mut aux_volumes);
relative_gap = graph.relative_gap(&volumes, &costs, &aux_volumes);
log_additional!(
EVENT_ASSIGNMENT_ITERATION,
"MSA iteration",
iteration = iteration,
gap = format!("{:.8}", relative_gap)
);
if relative_gap.abs() < config.convergence_gap {
converged = true;
break;
}
let lambda = 1.0 / (iteration as f64 + 1.0);
for i in 0..n {
volumes[i] += lambda * (aux_volumes[i] - volumes[i]);
}
}
graph.compute_costs(&volumes, vdf, &mut costs);
log_main!(
EVENT_CONVERGENCE,
"MSA complete",
iterations = iteration,
gap = format!("{:.8}", relative_gap),
converged = converged
);
Ok(AssignmentResult {
link_volumes: graph.volumes_to_hashmap(&volumes),
link_costs: graph.costs_to_hashmap(&costs),
iterations: iteration,
relative_gap,
converged,
})
}
}