use super::util::*;
use crate::priority_queue::PriorityQueue;
use std::collections::BTreeMap;
use super::dual_module::EdgeWeightModifier;
#[derive(Debug, Clone)]
pub struct CompleteGraph {
pub vertex_num: VertexNum,
pub vertices: Vec<CompleteGraphVertex>,
active_timestamp: FastClearTimestamp,
pub edge_modifier: EdgeWeightModifier,
pub weighted_edges: Vec<(VertexIndex, VertexIndex, Weight)>,
}
#[derive(Debug, Clone)]
pub struct CompleteGraphVertex {
pub edges: BTreeMap<VertexIndex, Weight>,
timestamp: FastClearTimestamp,
}
impl CompleteGraph {
pub fn new(vertex_num: VertexNum, weighted_edges: &[(VertexIndex, VertexIndex, Weight)]) -> Self {
let mut vertices: Vec<CompleteGraphVertex> = (0..vertex_num).map(|_| CompleteGraphVertex { edges: BTreeMap::new(), timestamp: 0, }).collect();
for &(i, j, weight) in weighted_edges.iter() {
vertices[i as usize].edges.insert(j, weight);
vertices[j as usize].edges.insert(i, weight);
}
Self {
vertex_num,
vertices,
active_timestamp: 0,
edge_modifier: EdgeWeightModifier::new(),
weighted_edges: weighted_edges.to_owned(),
}
}
pub fn reset(&mut self) {
while self.edge_modifier.has_modified_edges() {
let (edge_index, original_weight) = self.edge_modifier.pop_modified_edge();
let (vertex_idx_1, vertex_idx_2, _) = &self.weighted_edges[edge_index as usize];
let vertex_1 = &mut self.vertices[*vertex_idx_1 as usize];
assert_eq!(vertex_1.edges.insert(*vertex_idx_2, original_weight), Some(0), "previous weight should be 0");
let vertex_2 = &mut self.vertices[*vertex_idx_2 as usize];
assert_eq!(vertex_2.edges.insert(*vertex_idx_1, original_weight), Some(0), "previous weight should be 0");
self.weighted_edges[edge_index as usize] = (*vertex_idx_1, *vertex_idx_2, original_weight);
}
}
fn load_edge_modifier(&mut self, edge_modifier: &[(EdgeIndex, Weight)]) {
assert!(!self.edge_modifier.has_modified_edges(), "the current erasure modifier is not clean, probably forget to clean the state?");
for (edge_index, target_weight) in edge_modifier.iter() {
let (vertex_idx_1, vertex_idx_2, original_weight) = &self.weighted_edges[*edge_index as usize];
let vertex_1 = &mut self.vertices[*vertex_idx_1 as usize];
vertex_1.edges.insert(*vertex_idx_2, *target_weight);
let vertex_2 = &mut self.vertices[*vertex_idx_2 as usize];
vertex_2.edges.insert(*vertex_idx_1, *target_weight);
self.edge_modifier.push_modified_edge(*edge_index, *original_weight);
self.weighted_edges[*edge_index as usize] = (*vertex_idx_1, *vertex_idx_2, *target_weight);
}
}
pub fn load_erasures(&mut self, erasures: &[EdgeIndex]) {
let edge_modifier: Vec<_> = erasures.iter().map(|edge_index| (*edge_index, 0)).collect();
self.load_edge_modifier(&edge_modifier);
}
pub fn invalidate_previous_dijkstra(&mut self) -> usize {
if self.active_timestamp == FastClearTimestamp::MAX { self.active_timestamp = 0;
for i in 0..self.vertex_num {
self.vertices[i as usize].timestamp = 0; }
}
self.active_timestamp += 1; self.active_timestamp
}
pub fn all_edges_with_terminate(&mut self, vertex: VertexIndex, terminate: VertexIndex) -> BTreeMap<VertexIndex, (VertexIndex, Weight)> {
let active_timestamp = self.invalidate_previous_dijkstra();
let mut pq = PriorityQueue::<EdgeIndex, PriorityElement>::new();
pq.push(vertex, PriorityElement::new(0, vertex));
let mut computed_edges = BTreeMap::<VertexIndex, (VertexIndex, Weight)>::new(); loop { if pq.is_empty() {
break
}
let (target, PriorityElement { weight, previous }) = pq.pop().unwrap();
debug_assert!({
!computed_edges.contains_key(&target) });
self.vertices[target as usize].timestamp = active_timestamp; if target != vertex {
computed_edges.insert(target, (previous, weight));
if target == terminate {
break }
}
for (&neighbor, &neighbor_weight) in self.vertices[target as usize].edges.iter() {
let edge_weight = weight + neighbor_weight;
if let Some(PriorityElement { weight: existing_weight, previous: existing_previous }) = pq.get_priority(&neighbor) {
let mut update = &edge_weight < existing_weight;
if &edge_weight == existing_weight {
let distance = if neighbor > previous { neighbor - previous } else { previous - neighbor };
let existing_distance = if &neighbor > existing_previous { neighbor - existing_previous } else { existing_previous - neighbor };
if distance < existing_distance || (distance == existing_distance && &previous < existing_previous) {
update = true;
}
}
if update {
pq.change_priority(&neighbor, PriorityElement::new(edge_weight, target));
}
} else { if self.vertices[neighbor as usize].timestamp != active_timestamp {
pq.push(neighbor, PriorityElement::new(edge_weight, target));
}
}
}
}
computed_edges
}
pub fn all_edges(&mut self, vertex: VertexIndex) -> BTreeMap<VertexIndex, (VertexIndex, Weight)> {
self.all_edges_with_terminate(vertex, VertexIndex::MAX)
}
pub fn get_path(&mut self, a: VertexIndex, b: VertexIndex) -> (Vec<(VertexIndex, Weight)>, Weight) {
assert_ne!(a, b, "cannot get path between the same vertex");
let edges = self.all_edges_with_terminate(a, b);
let mut vertex = b;
let mut path = Vec::new();
loop {
if vertex == a {
break
}
let &(previous, weight) = &edges[&vertex];
path.push((vertex, weight));
if path.len() > 1 {
let previous_index = path.len() - 2;
path[previous_index].1 -= weight;
}
vertex = previous;
}
path.reverse();
(path, edges[&b].1)
}
}
#[derive(Eq, Debug)]
pub struct PriorityElement {
pub weight: Weight,
pub previous: VertexIndex,
}
impl std::cmp::PartialEq for PriorityElement {
#[inline]
fn eq(&self, other: &PriorityElement) -> bool {
self.weight == other.weight
}
}
impl std::cmp::PartialOrd for PriorityElement {
#[inline]
fn partial_cmp(&self, other: &PriorityElement) -> Option<std::cmp::Ordering> {
other.weight.partial_cmp(&self.weight) }
}
impl std::cmp::Ord for PriorityElement {
#[inline]
fn cmp(&self, other: &PriorityElement) -> std::cmp::Ordering {
other.weight.cmp(&self.weight) }
}
impl PriorityElement {
pub fn new(weight: Weight, previous: VertexIndex) -> Self {
Self {
weight,
previous,
}
}
}