1use super::dual_module::EdgeWeightModifier;
2use super::util::*;
3use crate::priority_queue::PriorityQueue;
4use crate::rayon::prelude::*;
5use std::collections::BTreeMap;
6
7#[derive(Debug, Clone)]
9pub struct CompleteGraph {
10 pub vertex_num: VertexNum,
12 pub vertices: Vec<CompleteGraphVertex>,
14 active_timestamp: FastClearTimestamp,
16 pub edge_modifier: EdgeWeightModifier,
18 pub weighted_edges: Vec<(VertexIndex, VertexIndex, Weight)>,
20}
21
22#[derive(Debug, Clone)]
23pub struct CompleteGraphVertex {
24 pub edges: BTreeMap<VertexIndex, Weight>,
26 timestamp: FastClearTimestamp,
28}
29
30impl CompleteGraph {
31 #[allow(clippy::unnecessary_cast)]
33 pub fn new(vertex_num: VertexNum, weighted_edges: &[(VertexIndex, VertexIndex, Weight)]) -> Self {
34 let mut vertices: Vec<CompleteGraphVertex> = (0..vertex_num)
35 .map(|_| CompleteGraphVertex {
36 edges: BTreeMap::new(),
37 timestamp: 0,
38 })
39 .collect();
40 for &(i, j, weight) in weighted_edges.iter() {
41 vertices[i as usize].edges.insert(j, weight);
42 vertices[j as usize].edges.insert(i, weight);
43 }
44 Self {
45 vertex_num,
46 vertices,
47 active_timestamp: 0,
48 edge_modifier: EdgeWeightModifier::new(),
49 weighted_edges: weighted_edges.to_owned(),
50 }
51 }
52
53 #[allow(clippy::unnecessary_cast)]
55 pub fn reset(&mut self) {
56 while self.edge_modifier.has_modified_edges() {
58 let (edge_index, original_weight) = self.edge_modifier.pop_modified_edge();
59 let (vertex_idx_1, vertex_idx_2, _) = &self.weighted_edges[edge_index as usize];
60 let vertex_1 = &mut self.vertices[*vertex_idx_1 as usize];
61 vertex_1.edges.insert(*vertex_idx_2, original_weight);
62 let vertex_2 = &mut self.vertices[*vertex_idx_2 as usize];
63 vertex_2.edges.insert(*vertex_idx_1, original_weight);
64 self.weighted_edges[edge_index as usize] = (*vertex_idx_1, *vertex_idx_2, original_weight);
65 }
66 }
67
68 #[allow(clippy::unnecessary_cast)]
69 fn load_edge_modifier(&mut self, edge_modifier: &[(EdgeIndex, Weight)]) {
70 assert!(
71 !self.edge_modifier.has_modified_edges(),
72 "the current erasure modifier is not clean, probably forget to clean the state?"
73 );
74 for (edge_index, target_weight) in edge_modifier.iter() {
75 let (vertex_idx_1, vertex_idx_2, original_weight) = &self.weighted_edges[*edge_index as usize];
76 let vertex_1 = &mut self.vertices[*vertex_idx_1 as usize];
77 vertex_1.edges.insert(*vertex_idx_2, *target_weight);
78 let vertex_2 = &mut self.vertices[*vertex_idx_2 as usize];
79 vertex_2.edges.insert(*vertex_idx_1, *target_weight);
80 self.edge_modifier.push_modified_edge(*edge_index, *original_weight);
81 self.weighted_edges[*edge_index as usize] = (*vertex_idx_1, *vertex_idx_2, *target_weight);
82 }
83 }
84
85 pub fn load_erasures(&mut self, erasures: &[EdgeIndex]) {
87 let edge_modifier: Vec<_> = erasures.iter().map(|edge_index| (*edge_index, 0)).collect();
88 self.load_edge_modifier(&edge_modifier);
89 }
90
91 pub fn load_dynamic_weights(&mut self, dynamic_weights: &[(EdgeIndex, Weight)]) {
92 let edge_modifier = dynamic_weights.to_vec();
93 self.load_edge_modifier(&edge_modifier);
94 }
95
96 #[allow(clippy::unnecessary_cast)]
98 pub fn invalidate_previous_dijkstra(&mut self) -> usize {
99 if self.active_timestamp == FastClearTimestamp::MAX {
100 self.active_timestamp = 0;
102 for i in 0..self.vertex_num {
103 self.vertices[i as usize].timestamp = 0; }
105 }
106 self.active_timestamp += 1; self.active_timestamp
108 }
109
110 #[allow(clippy::unnecessary_cast)]
112 pub fn all_edges_with_terminate(
113 &mut self,
114 vertex: VertexIndex,
115 terminate: VertexIndex,
116 ) -> BTreeMap<VertexIndex, (VertexIndex, Weight)> {
117 let active_timestamp = self.invalidate_previous_dijkstra();
118 let mut pq = PriorityQueue::<EdgeIndex, PriorityElement>::new();
119 pq.push(vertex, PriorityElement::new(0, vertex));
120 let mut computed_edges = BTreeMap::<VertexIndex, (VertexIndex, Weight)>::new(); loop {
122 if pq.is_empty() {
124 break;
125 }
126 let (target, PriorityElement { weight, previous }) = pq.pop().unwrap();
127 debug_assert!({
129 !computed_edges.contains_key(&target) });
131 self.vertices[target as usize].timestamp = active_timestamp; if target != vertex {
134 computed_edges.insert(target, (previous, weight));
135 if target == terminate {
136 break; }
138 }
139 for (&neighbor, &neighbor_weight) in self.vertices[target as usize].edges.iter() {
141 let edge_weight = weight + neighbor_weight;
142 if let Some(PriorityElement {
143 weight: existing_weight,
144 previous: existing_previous,
145 }) = pq.get_priority(&neighbor)
146 {
147 let mut update = &edge_weight < existing_weight;
150 if &edge_weight == existing_weight {
151 let distance = if neighbor > previous {
152 neighbor - previous
153 } else {
154 previous - neighbor
155 };
156 let existing_distance = if &neighbor > existing_previous {
157 neighbor - existing_previous
158 } else {
159 existing_previous - neighbor
160 };
161 if distance < existing_distance || (distance == existing_distance && &previous < existing_previous) {
163 update = true;
164 }
165 }
166 if update {
167 pq.change_priority(&neighbor, PriorityElement::new(edge_weight, target));
168 }
169 } else {
170 if self.vertices[neighbor as usize].timestamp != active_timestamp {
172 pq.push(neighbor, PriorityElement::new(edge_weight, target));
173 }
174 }
175 }
176 }
177 computed_edges
179 }
180
181 pub fn all_edges(&mut self, vertex: VertexIndex) -> BTreeMap<VertexIndex, (VertexIndex, Weight)> {
183 self.all_edges_with_terminate(vertex, VertexIndex::MAX)
184 }
185
186 pub fn get_path(&mut self, a: VertexIndex, b: VertexIndex) -> (Vec<(VertexIndex, Weight)>, Weight) {
188 assert_ne!(a, b, "cannot get path between the same vertex");
189 let edges = self.all_edges_with_terminate(a, b);
190 let mut vertex = b;
192 let mut path = Vec::new();
193 loop {
194 if vertex == a {
195 break;
196 }
197 let &(previous, weight) = &edges[&vertex];
198 path.push((vertex, weight));
199 if path.len() > 1 {
200 let previous_index = path.len() - 2;
201 path[previous_index].1 -= weight;
202 }
203 vertex = previous;
204 }
205 path.reverse();
206 (path, edges[&b].1)
207 }
208}
209
210#[derive(Clone)]
211pub struct PrebuiltCompleteGraph {
212 pub vertex_num: VertexNum,
214 pub edges: Vec<BTreeMap<VertexIndex, Weight>>,
216 pub virtual_boundary_weight: Vec<Option<(VertexIndex, Weight)>>,
218}
219
220impl PrebuiltCompleteGraph {
221 #[allow(clippy::unnecessary_cast)]
222 pub fn new_threaded(initializer: &SolverInitializer, thread_pool_size: usize) -> Self {
223 let mut thread_pool_builder = rayon::ThreadPoolBuilder::new();
224 if thread_pool_size != 0 {
225 thread_pool_builder = thread_pool_builder.num_threads(thread_pool_size);
226 }
227 let thread_pool = thread_pool_builder.build().expect("creating thread pool failed");
228 let vertex_num = initializer.vertex_num as usize;
229 let mut is_virtual = vec![false; vertex_num];
231 for &virtual_vertex in initializer.virtual_vertices.iter() {
232 is_virtual[virtual_vertex as usize] = true;
233 }
234 type Result = (BTreeMap<VertexIndex, Weight>, Option<(VertexIndex, Weight)>);
235 let mut results: Vec<Result> = vec![];
236 thread_pool.scope(|_| {
237 (0..vertex_num)
238 .into_par_iter()
239 .map(|vertex_index| {
240 let mut complete_graph = CompleteGraph::new(initializer.vertex_num, &initializer.weighted_edges);
241 let mut edges = BTreeMap::new();
242 let mut virtual_boundary_weight = None;
243 if !is_virtual[vertex_index] {
244 let complete_graph_edges = complete_graph.all_edges(vertex_index as VertexIndex);
246 let mut boundary: Option<(VertexIndex, Weight)> = None;
247 for (&peer, &(_, weight)) in complete_graph_edges.iter() {
248 if !is_virtual[peer as usize] {
249 edges.insert(peer, weight);
250 }
251 if is_virtual[peer as usize] && (boundary.is_none() || weight < boundary.as_ref().unwrap().1) {
252 boundary = Some((peer, weight));
253 }
254 }
255 virtual_boundary_weight = boundary;
256 }
257 (edges, virtual_boundary_weight)
258 })
259 .collect_into_vec(&mut results);
260 });
261 type UnzipResult = (Vec<BTreeMap<VertexIndex, Weight>>, Vec<Option<(VertexIndex, Weight)>>);
263 let (mut edges, virtual_boundary_weight): UnzipResult = results.into_iter().unzip();
264 let mut to_be_removed_vec: Vec<Vec<VertexIndex>> = vec![];
265 thread_pool.scope(|_| {
266 (0..vertex_num)
267 .into_par_iter()
268 .map(|vertex_index| {
269 let mut to_be_removed = vec![];
270 if !is_virtual[vertex_index] {
271 for (&peer, &weight) in edges[vertex_index].iter() {
272 let boundary_weight = if let Some((_, weight)) = virtual_boundary_weight[vertex_index as usize] {
273 weight
274 } else {
275 Weight::MAX
276 };
277 let boundary_weight_peer = if let Some((_, weight)) = virtual_boundary_weight[peer as usize] {
278 weight
279 } else {
280 Weight::MAX
281 };
282 if boundary_weight != Weight::MAX
283 && boundary_weight_peer != Weight::MAX
284 && weight > boundary_weight + boundary_weight_peer
285 {
286 to_be_removed.push(peer);
287 }
288 }
289 }
290 to_be_removed
291 })
292 .collect_into_vec(&mut to_be_removed_vec);
293 });
294 for vertex_index in 0..vertex_num {
295 for peer in to_be_removed_vec[vertex_index].iter() {
296 edges[vertex_index].remove(peer);
297 }
298 }
299 Self {
300 vertex_num: initializer.vertex_num,
301 edges,
302 virtual_boundary_weight,
303 }
304 }
305
306 pub fn new(initializer: &SolverInitializer) -> Self {
307 Self::new_threaded(initializer, 1)
308 }
309
310 #[allow(clippy::unnecessary_cast)]
311 pub fn get_edge_weight(&self, vertex_1: VertexIndex, vertex_2: VertexIndex) -> Option<Weight> {
312 self.edges[vertex_1 as usize].get(&vertex_2).cloned()
313 }
314
315 #[allow(clippy::unnecessary_cast)]
316 pub fn get_boundary_weight(&self, vertex_index: VertexIndex) -> Option<(VertexIndex, Weight)> {
317 self.virtual_boundary_weight[vertex_index as usize]
318 }
319}
320
321#[derive(Eq, Debug)]
322pub struct PriorityElement {
323 pub weight: Weight,
324 pub previous: VertexIndex,
325}
326
327impl std::cmp::PartialEq for PriorityElement {
328 #[inline]
329 fn eq(&self, other: &PriorityElement) -> bool {
330 self.weight == other.weight
331 }
332}
333
334impl std::cmp::PartialOrd for PriorityElement {
335 #[inline]
336 fn partial_cmp(&self, other: &PriorityElement) -> Option<std::cmp::Ordering> {
337 Some(self.cmp(other))
338 }
339}
340
341impl std::cmp::Ord for PriorityElement {
342 #[inline]
343 fn cmp(&self, other: &PriorityElement) -> std::cmp::Ordering {
344 other.weight.cmp(&self.weight) }
346}
347
348impl PriorityElement {
349 pub fn new(weight: Weight, previous: VertexIndex) -> Self {
350 Self { weight, previous }
351 }
352}