1#![cfg_attr(feature = "unsafe_pointer", allow(dropping_references))]
7
8use core::cmp::Ordering;
9use std::collections::{BTreeMap, HashSet};
10use std::num::NonZeroUsize;
11#[cfg(not(feature = "dangerous_pointer"))]
12use std::sync::Arc;
13
14use nonzero::nonzero as nz;
15
16use crate::derivative::Derivative;
17
18use super::pointers::*;
19use super::util::*;
20use super::visualize::*;
21
22#[derive(Derivative, Clone)]
24#[derivative(Debug)]
25pub enum DualNodeClass {
26 Blossom {
27 nodes_circle: Vec<DualNodeWeak>,
28 touching_children: Vec<(DualNodeWeak, DualNodeWeak)>,
29 },
30 DefectVertex {
31 defect_index: VertexIndex,
32 },
33}
34
35impl DualNodeClass {
36 pub fn is_blossom(&self) -> bool {
37 matches!(self, Self::Blossom { .. })
38 }
39}
40
41#[derive(Derivative, PartialEq, Eq, Clone, Copy)]
43#[derivative(Debug)]
44pub enum DualNodeGrowState {
45 Grow,
46 Stay,
47 Shrink,
48}
49
50impl DualNodeGrowState {
51 pub fn is_against(&self, other: &Self) -> bool {
52 matches!(
53 (self, other),
54 (Self::Grow, Self::Grow | Self::Stay) | (Self::Stay, Self::Grow)
55 )
56 }
57}
58
59#[derive(Derivative)]
61#[derivative(Debug)]
62pub struct SyncRequest {
63 pub mirror_unit_weak: PartitionUnitWeak,
65 pub vertex_index: VertexIndex,
67 pub propagated_dual_node: Option<(DualNodeWeak, Weight, VertexIndex)>,
71 pub propagated_grandson_dual_node: Option<(DualNodeWeak, Weight, VertexIndex)>,
73}
74
75impl SyncRequest {
76 pub fn update(&self) {
78 if let Some((weak, ..)) = &self.propagated_dual_node {
79 weak.upgrade_force().update();
80 }
81 if let Some((weak, ..)) = &self.propagated_grandson_dual_node {
82 weak.upgrade_force().update();
83 }
84 }
85}
86
87#[derive(Derivative, PartialEq, Eq, Clone)]
91#[derivative(Debug)]
92pub enum MaxUpdateLength {
93 NonZeroGrow((Weight, bool)),
95 Conflicting((DualNodePtr, DualNodePtr), (DualNodePtr, DualNodePtr)), TouchingVirtual((DualNodePtr, DualNodePtr), (VertexIndex, bool)), BlossomNeedExpand(DualNodePtr),
101 VertexShrinkStop((DualNodePtr, Option<(DualNodePtr, DualNodePtr)>)),
105}
106
107cfg_if::cfg_if! {
108 if #[cfg(feature="ordered_conflicts")] {
109 use std::collections::BinaryHeap;
110 pub type ConflictList = BinaryHeap<MaxUpdateLength>;
111 } else {
112 pub type ConflictList = Vec<MaxUpdateLength>;
113 }
114}
115
116#[derive(Derivative, Clone)]
117#[derivative(Debug)]
118pub enum GroupMaxUpdateLength {
119 NonZeroGrow((Weight, bool)),
121 Conflicts((ConflictList, BTreeMap<VertexIndex, MaxUpdateLength>)),
123}
124
125impl Default for GroupMaxUpdateLength {
126 fn default() -> Self {
127 Self::new()
128 }
129}
130
131impl GroupMaxUpdateLength {
132 pub fn new() -> Self {
133 Self::NonZeroGrow((Weight::MAX, false))
134 }
135
136 #[inline(never)]
138 pub fn update(&self) {
139 if let Self::Conflicts((list, pending_stops)) = &self {
140 for max_update_length in list.iter() {
141 max_update_length.update();
142 }
143 for (_, max_update_length) in pending_stops.iter() {
144 max_update_length.update();
145 }
146 }
147 }
148
149 pub fn add_pending_stop(
150 list: &mut ConflictList,
151 pending_stops: &mut BTreeMap<VertexIndex, MaxUpdateLength>,
152 max_update_length: MaxUpdateLength,
153 ) {
154 if let Some(dual_node_ptr) = max_update_length.get_vertex_shrink_stop() {
155 let vertex_index = dual_node_ptr.get_representative_vertex();
156 if let Some(existing_length) = pending_stops.get(&vertex_index) {
157 if let MaxUpdateLength::VertexShrinkStop((_, Some(weak_pair))) = &max_update_length {
158 if let MaxUpdateLength::VertexShrinkStop((_, Some(existing_weak_pair))) = existing_length {
160 if weak_pair.0 != existing_weak_pair.0 {
161 list.push(MaxUpdateLength::Conflicting(weak_pair.clone(), existing_weak_pair.clone()));
163 pending_stops.remove(&vertex_index);
164 }
165 } else {
166 pending_stops.insert(vertex_index, max_update_length.clone());
167 }
169 }
170 } else {
171 pending_stops.insert(vertex_index, max_update_length);
172 }
173 } else {
174 list.push(max_update_length);
175 }
176 }
177
178 pub fn add(&mut self, max_update_length: MaxUpdateLength) {
179 match self {
180 Self::NonZeroGrow((current_length, current_has_empty_boundary_node)) => {
181 if let MaxUpdateLength::NonZeroGrow((length, has_empty_boundary_node)) = max_update_length {
182 *current_length = std::cmp::min(*current_length, length);
183 *current_has_empty_boundary_node |= has_empty_boundary_node;
184 } else {
186 let mut list = ConflictList::new();
187 let mut pending_stops = BTreeMap::new();
188 if let Some(dual_node_ptr) = max_update_length.get_vertex_shrink_stop() {
189 let vertex_index = dual_node_ptr.get_representative_vertex();
190 pending_stops.insert(vertex_index, max_update_length);
191 } else {
192 list.push(max_update_length);
193 }
194 *self = Self::Conflicts((list, pending_stops));
195 }
196 }
197 Self::Conflicts((list, pending_stops)) => {
198 if !matches!(max_update_length, MaxUpdateLength::NonZeroGrow(_)) {
200 Self::add_pending_stop(list, pending_stops, max_update_length);
201 }
202 }
203 }
204 }
205
206 pub fn extend(&mut self, other: Self) {
207 if other.is_empty() {
208 return; }
210 match self {
211 Self::NonZeroGrow(current_length) => match other {
212 Self::NonZeroGrow(length) => {
213 *current_length = std::cmp::min(*current_length, length);
214 }
215 Self::Conflicts((mut other_list, mut other_pending_stops)) => {
216 let mut list = ConflictList::new();
217 let mut pending_stops = BTreeMap::new();
218 std::mem::swap(&mut list, &mut other_list);
219 std::mem::swap(&mut pending_stops, &mut other_pending_stops);
220 *self = Self::Conflicts((list, pending_stops));
221 }
222 },
223 Self::Conflicts((list, pending_stops)) => {
224 if let Self::Conflicts((other_list, other_pending_stops)) = other {
225 list.extend(other_list);
226 for (_, max_update_length) in other_pending_stops.into_iter() {
227 Self::add_pending_stop(list, pending_stops, max_update_length);
228 }
229 } }
231 }
232 }
233
234 pub fn is_empty(&self) -> bool {
235 matches!(self, Self::NonZeroGrow((Weight::MAX, _))) }
237
238 pub fn is_active(&self) -> bool {
239 !matches!(self, Self::NonZeroGrow((Weight::MAX, false))) }
241
242 pub fn get_none_zero_growth(&self) -> Option<Weight> {
243 match self {
244 Self::NonZeroGrow((length, _has_empty_boundary_node)) => {
245 debug_assert!(
246 *length != Weight::MAX,
247 "please call GroupMaxUpdateLength::is_empty to check if this group is empty"
248 );
249 Some(*length)
250 }
251 _ => None,
252 }
253 }
254
255 pub fn pop(&mut self) -> Option<MaxUpdateLength> {
256 match self {
257 Self::NonZeroGrow(_) => {
258 panic!("please call GroupMaxUpdateLength::get_none_zero_growth to check if this group is none_zero_growth");
259 }
260 Self::Conflicts((list, pending_stops)) => {
261 list.pop().or(if let Some(key) = pending_stops.keys().next().cloned() {
262 pending_stops.remove(&key)
263 } else {
264 None
265 })
266 }
267 }
268 }
269
270 pub fn peek(&self) -> Option<&MaxUpdateLength> {
271 match self {
272 Self::NonZeroGrow(_) => {
273 panic!("please call GroupMaxUpdateLength::get_none_zero_growth to check if this group is none_zero_growth");
274 }
275 Self::Conflicts((list, pending_stops)) => {
276 cfg_if::cfg_if! {
277 if #[cfg(feature="ordered_conflicts")] {
278 let peek_element = list.peek();
279 } else {
280 let peek_element = list.last();
281 }
282 }
283 peek_element.or(if pending_stops.is_empty() {
284 None
285 } else {
286 pending_stops.values().next()
287 })
288 }
289 }
290 }
291}
292
293#[derive(Derivative, Clone)]
295#[derivative(Debug)]
296pub struct DualNode {
297 pub index: NodeIndex,
299 pub class: DualNodeClass,
301 pub grow_state: DualNodeGrowState,
303 pub parent_blossom: Option<DualNodeWeak>,
305 pub dual_variable_cache: (Weight, Weight),
307 pub belonging: DualModuleInterfaceWeak,
309 pub defect_size: NonZeroUsize,
311}
312
313impl DualNode {
314 pub fn get_dual_variable(&self, interface: &DualModuleInterface) -> Weight {
316 let (last_dual_variable, last_global_progress) = self.dual_variable_cache;
317 match self.grow_state {
318 DualNodeGrowState::Grow => last_dual_variable + (interface.dual_variable_global_progress - last_global_progress),
319 DualNodeGrowState::Stay => last_dual_variable,
320 DualNodeGrowState::Shrink => {
321 last_dual_variable - (interface.dual_variable_global_progress - last_global_progress)
322 }
323 }
324 }
325}
326
327pub type DualNodePtr = ArcManualSafeLock<DualNode>;
329pub type DualNodeWeak = WeakManualSafeLock<DualNode>;
330
331impl Ord for DualNodePtr {
332 fn cmp(&self, other: &Self) -> Ordering {
334 cfg_if::cfg_if! {
335 if #[cfg(feature="dangerous_pointer")] {
336 let node1 = self.read_recursive();
337 let node2 = other.read_recursive();
338 node1.index.cmp(&node2.index)
339 } else {
340 if false { let ptr1 = Arc::as_ptr(self.ptr());
342 let ptr2 = Arc::as_ptr(other.ptr());
343 ptr1.cmp(&ptr2)
346 } else {
347 let node1 = self.read_recursive();
348 let node2 = other.read_recursive();
349 node1.index.cmp(&node2.index)
350 }
351 }
352 }
353 }
354}
355
356impl PartialOrd for DualNodePtr {
357 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
358 Some(self.cmp(other))
359 }
360}
361
362impl std::fmt::Debug for DualNodePtr {
363 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
364 self.update(); let dual_node = self.read_recursive(); write!(f, "{}", dual_node.index)
367 }
368}
369
370impl std::fmt::Debug for DualNodeWeak {
371 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
372 self.upgrade_force().fmt(f)
373 }
374}
375
376impl DualNodePtr {
377 #[allow(clippy::needless_borrow)]
379 pub fn update(&self) -> &Self {
380 let mut current_belonging = self.read_recursive().belonging.upgrade_force();
381 let mut bias = 0;
382 let mut node = self.write();
383 while current_belonging.read_recursive().parent.is_some() {
384 let belonging_interface = current_belonging.read_recursive();
385 bias += belonging_interface.index_bias;
386 let new_current_belonging = belonging_interface.parent.clone().unwrap().upgrade_force();
387 let dual_variable = node.get_dual_variable(&belonging_interface); node.dual_variable_cache = (dual_variable, 0); drop(belonging_interface);
390 current_belonging = new_current_belonging;
391 }
392 node.belonging = current_belonging.downgrade();
393 node.index += bias;
394 self
395 }
396
397 pub fn updated_index(&self) -> NodeIndex {
398 self.update();
399 self.read_recursive().index
400 }
401
402 fn set_grow_state(&self, grow_state: DualNodeGrowState) {
404 let mut dual_node = self.write();
405 debug_assert!(
406 dual_node.parent_blossom.is_none(),
407 "setting node grow state inside a blossom forbidden"
408 );
409 dual_node.grow_state = grow_state;
410 }
411
412 pub fn get_ancestor_blossom(&self) -> DualNodePtr {
414 let dual_node = self.read_recursive();
415 match &dual_node.parent_blossom {
416 Some(ptr) => ptr.upgrade_force().get_ancestor_blossom(),
417 None => self.clone(),
418 }
419 }
420
421 pub fn get_secondary_ancestor_blossom(&self) -> DualNodePtr {
423 let mut secondary_ancestor = self.clone();
424 let mut ancestor = self
425 .read_recursive()
426 .parent_blossom
427 .as_ref()
428 .expect("secondary ancestor does not exist")
429 .upgrade_force();
430 loop {
431 let dual_node = ancestor.read_recursive();
432 let new_ancestor = match &dual_node.parent_blossom {
433 Some(weak) => weak.upgrade_force(),
434 None => {
435 return secondary_ancestor;
436 }
437 };
438 drop(dual_node);
439 secondary_ancestor = ancestor.clone();
440 ancestor = new_ancestor;
441 }
442 }
443
444 fn __get_all_vertices(&self, pending_vec: &mut Vec<VertexIndex>) {
445 let dual_node = self.read_recursive();
446 match &dual_node.class {
447 DualNodeClass::Blossom { nodes_circle, .. } => {
448 for node_ptr in nodes_circle.iter() {
449 node_ptr.upgrade_force().__get_all_vertices(pending_vec);
450 }
451 }
452 DualNodeClass::DefectVertex { defect_index } => {
453 pending_vec.push(*defect_index);
454 }
455 };
456 }
457
458 pub fn get_all_vertices(&self) -> Vec<VertexIndex> {
460 let mut pending_vec = vec![];
461 self.__get_all_vertices(&mut pending_vec);
462 pending_vec
463 }
464
465 pub fn get_representative_vertex(&self) -> VertexIndex {
467 let dual_node = self.read_recursive();
468 match &dual_node.class {
469 DualNodeClass::Blossom { nodes_circle, .. } => nodes_circle[0].upgrade_force().get_representative_vertex(),
470 DualNodeClass::DefectVertex { defect_index } => *defect_index,
471 }
472 }
473}
474
475#[derive(Derivative)]
478#[derivative(Debug)]
479pub struct DualModuleInterface {
480 pub unit_index: usize,
482 pub nodes: Vec<Option<DualNodePtr>>,
484 pub nodes_length: usize,
486 pub is_fusion: bool,
490 pub sum_grow_speed: Weight,
492 pub sum_dual_variables: Weight,
494 pub debug_print_actions: bool,
496 dual_variable_global_progress: Weight,
498 pub parent: Option<DualModuleInterfaceWeak>,
500 pub index_bias: NodeIndex,
502 pub children: Option<((DualModuleInterfaceWeak, NodeIndex), (DualModuleInterfaceWeak, NodeIndex))>,
505}
506
507pub type DualModuleInterfacePtr = ArcManualSafeLock<DualModuleInterface>;
508pub type DualModuleInterfaceWeak = WeakManualSafeLock<DualModuleInterface>;
509
510impl std::fmt::Debug for DualModuleInterfacePtr {
511 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
512 let interface = self.read_recursive();
513 write!(f, "{}", interface.unit_index)
514 }
515}
516
517impl std::fmt::Debug for DualModuleInterfaceWeak {
518 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
519 self.upgrade_force().fmt(f)
520 }
521}
522
523pub trait DualModuleImpl {
525 fn new_empty(initializer: &SolverInitializer) -> Self;
527
528 fn clear(&mut self);
530
531 fn add_dual_node(&mut self, dual_node_ptr: &DualNodePtr);
533
534 #[inline(always)]
535 fn add_defect_node(&mut self, dual_node_ptr: &DualNodePtr) {
537 debug_assert!(
538 {
539 let node = dual_node_ptr.read_recursive();
540 matches!(node.class, DualNodeClass::DefectVertex { .. })
541 },
542 "node class mismatch"
543 );
544 self.add_dual_node(dual_node_ptr)
545 }
546
547 #[inline(always)]
548 fn add_blossom(&mut self, dual_node_ptr: &DualNodePtr) {
550 debug_assert!(
551 {
552 let node = dual_node_ptr.read_recursive();
553 matches!(node.class, DualNodeClass::Blossom { .. })
554 },
555 "node class mismatch"
556 );
557 self.add_dual_node(dual_node_ptr)
558 }
559
560 fn remove_blossom(&mut self, dual_node_ptr: DualNodePtr);
563
564 fn set_grow_state(&mut self, dual_node_ptr: &DualNodePtr, grow_state: DualNodeGrowState);
566
567 fn compute_maximum_update_length_dual_node(
572 &mut self,
573 _dual_node_ptr: &DualNodePtr,
574 _is_grow: bool,
575 _simultaneous_update: bool,
576 ) -> MaxUpdateLength {
577 panic!("the dual module implementation doesn't support this function, please use another dual module")
578 }
579
580 fn compute_maximum_update_length(&mut self) -> GroupMaxUpdateLength;
583
584 fn grow_dual_node(&mut self, _dual_node_ptr: &DualNodePtr, _length: Weight) {
586 panic!("the dual module implementation doesn't support this function, please use another dual module")
587 }
588
589 fn grow(&mut self, length: Weight);
592
593 fn load_edge_modifier(&mut self, _edge_modifier: &[(EdgeIndex, Weight)]) {
596 unimplemented!(
597 "load_edge_modifier is an optional interface, and the current dual module implementation doesn't support it"
598 );
599 }
600
601 fn load_erasures(&mut self, erasures: &[EdgeIndex]) {
603 let edge_modifier: Vec<_> = erasures.iter().map(|edge_index| (*edge_index, 0)).collect();
604 self.load_edge_modifier(&edge_modifier);
605 }
606
607 fn load_dynamic_weights(&mut self, dynamic_weights: &[(EdgeIndex, Weight)]) {
608 let edge_modifier = dynamic_weights.to_vec();
609 self.load_edge_modifier(&edge_modifier);
610 }
611
612 fn prepare_nodes_shrink(&mut self, _nodes_circle: &[DualNodePtr]) -> &mut Vec<SyncRequest> {
614 panic!("the dual module implementation doesn't support this function, please use another dual module")
615 }
616
617 fn generate_profiler_report(&self) -> serde_json::Value {
619 json!({})
620 }
621
622 fn new_partitioned(_partitioned_initializer: &PartitionedSolverInitializer) -> Self
628 where
629 Self: std::marker::Sized,
630 {
631 panic!("the dual module implementation doesn't support this function, please use another dual module")
632 }
633
634 fn prepare_all(&mut self) -> &mut Vec<SyncRequest> {
636 panic!("the dual module implementation doesn't support this function, please use another dual module")
637 }
638
639 fn execute_sync_event(&mut self, _sync_event: &SyncRequest) {
641 panic!("the dual module implementation doesn't support this function, please use another dual module")
642 }
643
644 fn contains_dual_node(&self, _dual_node_ptr: &DualNodePtr) -> bool {
646 panic!("the dual module implementation doesn't support this function, please use another dual module")
647 }
648
649 fn contains_dual_nodes_any(&self, dual_node_ptrs: &[DualNodePtr]) -> bool {
651 for dual_node_ptr in dual_node_ptrs.iter() {
652 if self.contains_dual_node(dual_node_ptr) {
653 return true;
654 }
655 }
656 false
657 }
658
659 fn contains_vertex(&self, _vertex_index: VertexIndex) -> bool {
661 panic!("the dual module implementation doesn't support this function, please use another dual module")
662 }
663
664 fn bias_dual_node_index(&mut self, _bias: NodeIndex) {
666 panic!("the dual module implementation doesn't support this function, please use another dual module")
667 }
668}
669
670pub trait DualModuleParallelImpl {
672 type UnitType: DualModuleImpl + Send + Sync;
673
674 fn get_unit(&self, unit_index: usize) -> ArcManualSafeLock<Self::UnitType>;
675}
676
677impl FusionVisualizer for DualModuleInterfacePtr {
678 fn snapshot(&self, abbrev: bool) -> serde_json::Value {
679 let flattened_nodes = self.sanity_check().unwrap();
681 let interface = self.read_recursive();
682 let mut dual_nodes = Vec::<serde_json::Value>::new();
683 for dual_node_ptr in flattened_nodes.iter() {
684 if let Some(dual_node_ptr) = &dual_node_ptr {
685 let dual_node = dual_node_ptr.read_recursive();
686 dual_nodes.push(json!({
687 if abbrev { "o" } else { "blossom" }: match &dual_node.class {
688 DualNodeClass::Blossom { nodes_circle, .. } => Some(nodes_circle.iter().map(|node_ptr|
689 node_ptr.upgrade_force().read_recursive().index).collect::<Vec<NodeIndex>>()),
690 _ => None,
691 },
692 if abbrev { "t" } else { "touching_children" }: match &dual_node.class {
693 DualNodeClass::Blossom { touching_children, .. } => Some(touching_children.iter().map(|(node_ptr_1, node_ptr_2)|
694 (node_ptr_1.upgrade_force().read_recursive().index, node_ptr_2.upgrade_force().read_recursive().index)).collect::<Vec<(NodeIndex, NodeIndex)>>()),
695 _ => None,
696 },
697 if abbrev { "s" } else { "defect_vertex" }: match &dual_node.class {
698 DualNodeClass::DefectVertex { defect_index } => Some(defect_index),
699 _ => None,
700 },
701 if abbrev { "g" } else { "grow_state" }: match &dual_node.grow_state {
702 DualNodeGrowState::Grow => "grow",
703 DualNodeGrowState::Shrink => "shrink",
704 DualNodeGrowState::Stay => "stay",
705 },
706 if abbrev { "u" } else { "unit_growth" }: match &dual_node.grow_state {
707 DualNodeGrowState::Grow => 1,
708 DualNodeGrowState::Shrink => -1,
709 DualNodeGrowState::Stay => 0,
710 },
711 if abbrev { "p" } else { "parent_blossom" }: dual_node.parent_blossom.as_ref().map(|weak| weak.upgrade_force().read_recursive().index),
712 }));
713 } else {
714 dual_nodes.push(json!(null));
715 }
716 }
717 json!({
718 "interface": {
719 if abbrev { "s" } else { "sum_grow_speed" }: interface.sum_grow_speed,
720 if abbrev { "d" } else { "sum_dual_variables" }: interface.sum_dual_variables,
721 },
722 "dual_nodes": dual_nodes,
723 })
724 }
725}
726
727impl DualModuleInterface {
728 pub fn nodes_count(&self) -> NodeNum {
730 let mut count = self.nodes_length as NodeNum;
731 if let Some(((_, left_count), (_, right_count))) = &self.children {
732 count += left_count + right_count;
733 }
734 count
735 }
736
737 #[allow(clippy::unnecessary_cast)]
739 pub fn get_node(&self, relative_node_index: NodeIndex) -> Option<DualNodePtr> {
740 debug_assert!(relative_node_index < self.nodes_count(), "cannot find node in this interface");
741 let mut bias = 0;
742 if let Some(((left_weak, left_count), (right_weak, right_count))) = &self.children {
743 if relative_node_index < *left_count {
744 return left_weak.upgrade_force().read_recursive().get_node(relative_node_index);
746 } else if relative_node_index < *left_count + *right_count {
747 return right_weak
749 .upgrade_force()
750 .read_recursive()
751 .get_node(relative_node_index - *left_count);
752 }
753 bias = left_count + right_count;
754 }
755 self.nodes[(relative_node_index - bias) as usize].clone()
756 }
757
758 #[allow(clippy::unnecessary_cast)]
760 pub fn remove_node(&mut self, relative_node_index: NodeIndex) {
761 debug_assert!(relative_node_index < self.nodes_count(), "cannot find node in this interface");
762 let mut bias = 0;
763 if let Some(((left_weak, left_count), (right_weak, right_count))) = &self.children {
764 if relative_node_index < *left_count {
765 left_weak.upgrade_force().write().remove_node(relative_node_index);
767 return;
768 } else if relative_node_index < *left_count + *right_count {
769 right_weak
771 .upgrade_force()
772 .write()
773 .remove_node(relative_node_index - *left_count);
774 return;
775 }
776 bias = left_count + right_count;
777 }
778 self.nodes[(relative_node_index - bias) as usize] = None;
779 }
780}
781
782impl DualModuleInterfacePtr {
783 pub fn new_empty() -> Self {
785 Self::new_value(DualModuleInterface {
786 unit_index: 0, nodes: Vec::new(),
788 nodes_length: 0,
789 is_fusion: false,
790 sum_grow_speed: 0,
791 sum_dual_variables: 0,
792 debug_print_actions: false,
793 dual_variable_global_progress: 0,
794 parent: None,
795 index_bias: 0,
796 children: None,
797 })
798 }
799
800 pub fn new_load(syndrome_pattern: &SyndromePattern, dual_module_impl: &mut impl DualModuleImpl) -> Self {
802 let interface_ptr = Self::new_empty();
803 interface_ptr.load(syndrome_pattern, dual_module_impl);
804 interface_ptr
805 }
806
807 pub fn load(&self, syndrome_pattern: &SyndromePattern, dual_module_impl: &mut impl DualModuleImpl) {
808 for vertex_idx in syndrome_pattern.defect_vertices.iter() {
809 self.create_defect_node(*vertex_idx, dual_module_impl);
810 }
811 if !syndrome_pattern.erasures.is_empty() {
812 assert!(
813 syndrome_pattern.dynamic_weights.is_empty(),
814 "erasures and dynamic_weights cannot be provided at the same time"
815 );
816 dual_module_impl.load_erasures(&syndrome_pattern.erasures);
817 }
818 if !syndrome_pattern.dynamic_weights.is_empty() {
819 dual_module_impl.load_dynamic_weights(&syndrome_pattern.dynamic_weights);
820 }
821 }
822
823 pub fn clear(&self) {
827 let mut interface = self.write();
828 interface.nodes_length = 0;
829 interface.sum_grow_speed = 0;
830 interface.sum_dual_variables = 0;
831 interface.dual_variable_global_progress = 0;
832 interface.is_fusion = false;
833 interface.parent = None;
834 interface.index_bias = 0;
835 interface.children = None;
836 }
837
838 pub fn flatten_nodes(&self, flattened_nodes: &mut Vec<Option<DualNodePtr>>) {
840 let interface = self.read_recursive();
841 let flattened_nodes_length = flattened_nodes.len() as NodeNum;
842 if let Some(((left_child_weak, _), (right_child_weak, _))) = &interface.children {
844 left_child_weak.upgrade_force().flatten_nodes(flattened_nodes);
845 right_child_weak.upgrade_force().flatten_nodes(flattened_nodes);
846 }
847 for node_index in 0..interface.nodes_length {
848 let dual_node_ptr = &interface.nodes[node_index];
849 if let Some(dual_node_ptr) = dual_node_ptr {
850 dual_node_ptr.update();
851 }
852 flattened_nodes.push(dual_node_ptr.clone());
853 }
854 debug_assert_eq!(
855 flattened_nodes.len() as NodeNum - flattened_nodes_length,
856 interface.nodes_count()
857 );
858 }
859
860 pub fn create_defect_node(&self, vertex_idx: VertexIndex, dual_module_impl: &mut impl DualModuleImpl) -> DualNodePtr {
861 let belonging = self.downgrade();
862 let mut interface = self.write();
863 interface.sum_grow_speed += 1;
864 let local_node_index = interface.nodes_length;
865 let node_index = interface.nodes_count();
866 let node_ptr = if !interface.is_fusion
868 && local_node_index < interface.nodes.len()
869 && interface.nodes[local_node_index].is_some()
870 {
871 let node_ptr = interface.nodes[local_node_index].take().unwrap();
872 let mut node = node_ptr.write();
873 node.index = node_index;
874 node.class = DualNodeClass::DefectVertex {
875 defect_index: vertex_idx,
876 };
877 node.grow_state = DualNodeGrowState::Grow;
878 node.parent_blossom = None;
879 node.dual_variable_cache = (0, interface.dual_variable_global_progress);
880 node.belonging = belonging;
881 node.defect_size = nz!(1usize);
882 drop(node);
883 node_ptr
884 } else {
885 DualNodePtr::new_value(DualNode {
886 index: node_index,
887 class: DualNodeClass::DefectVertex {
888 defect_index: vertex_idx,
889 },
890 grow_state: DualNodeGrowState::Grow,
891 parent_blossom: None,
892 dual_variable_cache: (0, interface.dual_variable_global_progress),
893 belonging,
894 defect_size: nz!(1usize),
895 })
896 };
897 interface.nodes_length += 1;
898 if interface.nodes.len() < interface.nodes_length {
899 interface.nodes.push(None);
900 }
901 let cloned_node_ptr = node_ptr.clone();
902 interface.nodes[local_node_index] = Some(node_ptr); drop(interface);
904 dual_module_impl.add_defect_node(&cloned_node_ptr);
905 cloned_node_ptr
906 }
907
908 pub fn check_ptr_belonging(&self, dual_node_ptr: &DualNodePtr) -> bool {
910 let interface = self.read_recursive();
911 let dual_node = dual_node_ptr.read_recursive();
912 if dual_node.index >= interface.nodes_count() {
913 return false;
914 }
915 if let Some(ptr) = interface.get_node(dual_node.index).as_ref() {
916 ptr == dual_node_ptr
917 } else {
918 false
919 }
920 }
921
922 pub fn create_blossom(
925 &self,
926 nodes_circle: Vec<DualNodePtr>,
927 mut touching_children: Vec<(DualNodeWeak, DualNodeWeak)>,
928 dual_module_impl: &mut impl DualModuleImpl,
929 ) -> DualNodePtr {
930 let belonging = self.downgrade();
931 let mut interface = self.write();
932 if touching_children.is_empty() {
933 touching_children = nodes_circle.iter().map(|ptr| (ptr.downgrade(), ptr.downgrade())).collect();
935 }
936 debug_assert_eq!(touching_children.len(), nodes_circle.len(), "circle length mismatch");
937 let local_node_index = interface.nodes_length;
938 let node_index = interface.nodes_count();
939 let defect_size = nodes_circle
940 .iter()
941 .map(|iter| iter.read_recursive().defect_size)
942 .reduce(|a, b| a.saturating_add(b.get()))
943 .unwrap();
944
945 let blossom_node_ptr = if !interface.is_fusion
946 && local_node_index < interface.nodes.len()
947 && interface.nodes[local_node_index].is_some()
948 {
949 let node_ptr = interface.nodes[local_node_index].take().unwrap();
950 let mut node = node_ptr.write();
951 node.index = node_index;
952 node.class = DualNodeClass::Blossom {
953 nodes_circle: vec![],
954 touching_children: vec![],
955 };
956 node.grow_state = DualNodeGrowState::Grow;
957 node.parent_blossom = None;
958 node.dual_variable_cache = (0, interface.dual_variable_global_progress);
959 node.belonging = belonging;
960 node.defect_size = defect_size;
961 drop(node);
962 node_ptr
963 } else {
964 DualNodePtr::new_value(DualNode {
965 index: node_index,
966 class: DualNodeClass::Blossom {
967 nodes_circle: vec![],
968 touching_children: vec![],
969 },
970 grow_state: DualNodeGrowState::Grow,
971 parent_blossom: None,
972 dual_variable_cache: (0, interface.dual_variable_global_progress),
973 belonging,
974 defect_size,
975 })
976 };
977 drop(interface);
978 for node_ptr in nodes_circle.iter() {
979 debug_assert!(
980 self.check_ptr_belonging(node_ptr),
981 "this ptr doesn't belong to this interface"
982 );
983 let node = node_ptr.read_recursive();
984 debug_assert!(
985 node.parent_blossom.is_none(),
986 "cannot create blossom on a node that already belongs to a blossom"
987 );
988 drop(node);
989 self.set_grow_state(node_ptr, DualNodeGrowState::Stay, dual_module_impl);
991 let mut node = node_ptr.write();
993 node.parent_blossom = Some(blossom_node_ptr.downgrade());
994 }
995 let mut interface = self.write();
996 if interface.debug_print_actions {
997 eprintln!("[create blossom] {:?} -> {}", nodes_circle, node_index);
998 }
999 let cloned_blossom_node_ptr = blossom_node_ptr.clone();
1000 {
1001 let mut node = blossom_node_ptr.write();
1003 node.class = DualNodeClass::Blossom {
1004 nodes_circle: nodes_circle.iter().map(|ptr| ptr.downgrade()).collect(),
1005 touching_children,
1006 };
1007 interface.nodes_length += 1;
1008 if interface.nodes.len() < interface.nodes_length {
1009 interface.nodes.push(None);
1010 }
1011 drop(node);
1012 interface.nodes[local_node_index] = Some(blossom_node_ptr); }
1014 interface.sum_grow_speed += 1;
1015 drop(interface);
1016 dual_module_impl.prepare_nodes_shrink(&nodes_circle);
1017 dual_module_impl.add_blossom(&cloned_blossom_node_ptr);
1018 cloned_blossom_node_ptr
1019 }
1020
1021 pub fn expand_blossom(&self, blossom_node_ptr: DualNodePtr, dual_module_impl: &mut impl DualModuleImpl) {
1025 let interface = self.read_recursive();
1026 if interface.debug_print_actions {
1027 let node = blossom_node_ptr.read_recursive();
1028 if let DualNodeClass::Blossom { nodes_circle, .. } = &node.class {
1029 eprintln!("[expand blossom] {:?} -> {:?}", blossom_node_ptr, nodes_circle);
1030 } else {
1031 unreachable!()
1032 }
1033 }
1034 let is_fusion = interface.is_fusion;
1035 drop(interface);
1036 if is_fusion {
1037 let node = blossom_node_ptr.read_recursive();
1039 if let DualNodeClass::Blossom { nodes_circle, .. } = &node.class {
1040 for node_weak in nodes_circle.iter() {
1041 node_weak.upgrade_force().update();
1042 }
1043 }
1044 }
1045 dual_module_impl.remove_blossom(blossom_node_ptr.clone());
1046 let mut interface = self.write();
1047 let node = blossom_node_ptr.read_recursive();
1048 match &node.grow_state {
1049 DualNodeGrowState::Grow => {
1050 interface.sum_grow_speed += -1;
1051 }
1052 DualNodeGrowState::Shrink => {
1053 interface.sum_grow_speed += 1;
1054 }
1055 DualNodeGrowState::Stay => {}
1056 }
1057 let node_idx = node.index;
1058 debug_assert!(
1059 interface.get_node(node_idx).is_some(),
1060 "the blossom should not be expanded before"
1061 );
1062 debug_assert!(
1063 interface.get_node(node_idx).as_ref().unwrap() == &blossom_node_ptr,
1064 "the blossom doesn't belong to this DualModuleInterface"
1065 );
1066 drop(interface);
1067 match &node.class {
1068 DualNodeClass::Blossom { nodes_circle, .. } => {
1069 for node_weak in nodes_circle.iter() {
1070 let node_ptr = node_weak.upgrade_force();
1071 let mut node = node_ptr.write();
1072 debug_assert!(
1073 node.parent_blossom.is_some()
1074 && node.parent_blossom.as_ref().unwrap() == &blossom_node_ptr.downgrade(),
1075 "internal error: parent blossom must be this blossom"
1076 );
1077 debug_assert!(
1078 node.grow_state == DualNodeGrowState::Stay,
1079 "internal error: children node must be DualNodeGrowState::Stay"
1080 );
1081 node.parent_blossom = None;
1082 drop(node);
1083 {
1084 self.set_grow_state(&node_ptr, DualNodeGrowState::Grow, dual_module_impl);
1088 }
1092 }
1093 }
1094 _ => {
1095 unreachable!()
1096 }
1097 }
1098 let mut interface = self.write();
1099 interface.remove_node(node_idx); }
1101
1102 #[allow(clippy::needless_borrow)]
1104 pub fn set_grow_state(
1105 &self,
1106 dual_node_ptr: &DualNodePtr,
1107 grow_state: DualNodeGrowState,
1108 dual_module_impl: &mut impl DualModuleImpl,
1109 ) {
1110 if self.read_recursive().is_fusion {
1111 dual_node_ptr.update(); }
1113 let mut interface = self.write();
1114 if interface.debug_print_actions {
1115 eprintln!("[set grow state] {:?} {:?}", dual_node_ptr, grow_state);
1116 }
1117 {
1118 let mut node = dual_node_ptr.write();
1120 match &node.grow_state {
1121 DualNodeGrowState::Grow => {
1122 interface.sum_grow_speed -= 1;
1123 }
1124 DualNodeGrowState::Shrink => {
1125 interface.sum_grow_speed += 1;
1126 }
1127 DualNodeGrowState::Stay => {}
1128 }
1129 match grow_state {
1130 DualNodeGrowState::Grow => {
1131 interface.sum_grow_speed += 1;
1132 }
1133 DualNodeGrowState::Shrink => {
1134 interface.sum_grow_speed -= 1;
1135 }
1136 DualNodeGrowState::Stay => {}
1137 }
1138 let current_dual_variable = node.get_dual_variable(&interface);
1139 node.dual_variable_cache = (current_dual_variable, interface.dual_variable_global_progress);
1140 }
1142 drop(interface);
1143 dual_module_impl.set_grow_state(dual_node_ptr, grow_state); dual_node_ptr.set_grow_state(grow_state);
1145 }
1146
1147 pub fn grow(&self, length: Weight, dual_module_impl: &mut impl DualModuleImpl) {
1149 dual_module_impl.grow(length);
1150 self.notify_grown(length);
1151 }
1152
1153 pub fn notify_grown(&self, length: Weight) {
1155 let mut interface = self.write();
1156 interface.sum_dual_variables += length * interface.sum_grow_speed;
1157 interface.dual_variable_global_progress += length;
1158 }
1159
1160 pub fn grow_iterative(&self, mut length: Weight, dual_module_impl: &mut impl DualModuleImpl) {
1162 while length > 0 {
1163 let max_update_length = dual_module_impl.compute_maximum_update_length();
1164 let safe_growth = max_update_length
1165 .get_none_zero_growth()
1166 .unwrap_or_else(|| panic!("iterative grow failed because of conflicts {max_update_length:?}"));
1167 let growth = std::cmp::min(length, safe_growth);
1168 self.grow(growth, dual_module_impl);
1169 length -= growth;
1170 }
1171 }
1172
1173 #[allow(clippy::unnecessary_cast)]
1175 #[allow(clippy::needless_borrow)]
1176 pub fn slow_fuse(&self, left: &Self, right: &Self) {
1177 let mut interface = self.write();
1178 interface.is_fusion = true; for other in [left, right] {
1180 let mut other_interface = other.write();
1181 other_interface.is_fusion = true;
1182 let bias = interface.nodes_length as NodeNum;
1183 for other_node_index in 0..other_interface.nodes_length as NodeNum {
1184 let node_ptr = &other_interface.nodes[other_node_index as usize];
1185 if let Some(node_ptr) = node_ptr {
1186 let mut node = node_ptr.write();
1187 debug_assert_eq!(node.index, other_node_index);
1188 node.index += bias;
1189 node.dual_variable_cache = (
1190 node.get_dual_variable(&other_interface),
1191 interface.dual_variable_global_progress,
1192 )
1193 }
1194 interface.nodes_length += 1;
1195 if interface.nodes.len() < interface.nodes_length {
1196 interface.nodes.push(None);
1197 }
1198 interface.nodes[(bias + other_node_index) as usize] = node_ptr.clone();
1199 }
1200 interface.sum_dual_variables += other_interface.sum_dual_variables;
1201 interface.sum_grow_speed += other_interface.sum_grow_speed;
1202 }
1203 }
1204
1205 pub fn fuse(&self, left: &Self, right: &Self) {
1207 let parent_weak = self.downgrade();
1208 let left_weak = left.downgrade();
1209 let right_weak = right.downgrade();
1210 let mut interface = self.write();
1211 interface.is_fusion = true; debug_assert_eq!(interface.nodes_length, 0, "fast fuse doesn't support non-empty fuse");
1213 debug_assert!(interface.children.is_none(), "cannot fuse twice");
1214 let mut left_interface = left.write();
1215 let mut right_interface = right.write();
1216 left_interface.is_fusion = true;
1217 right_interface.is_fusion = true;
1218 debug_assert!(left_interface.parent.is_none(), "cannot fuse an interface twice");
1219 debug_assert!(right_interface.parent.is_none(), "cannot fuse an interface twice");
1220 left_interface.parent = Some(parent_weak.clone());
1221 right_interface.parent = Some(parent_weak);
1222 left_interface.index_bias = 0;
1223 right_interface.index_bias = left_interface.nodes_count();
1224 interface.children = Some((
1225 (left_weak, left_interface.nodes_count()),
1226 (right_weak, right_interface.nodes_count()),
1227 ));
1228 for other_interface in [left_interface, right_interface] {
1229 interface.sum_dual_variables += other_interface.sum_dual_variables;
1230 interface.sum_grow_speed += other_interface.sum_grow_speed;
1231 }
1232 }
1233
1234 #[inline(never)]
1236 #[allow(clippy::unnecessary_cast)]
1237 #[allow(clippy::needless_borrow)]
1238 pub fn sanity_check(&self) -> Result<Vec<Option<DualNodePtr>>, String> {
1239 let mut flattened_nodes = vec![];
1240 self.flatten_nodes(&mut flattened_nodes);
1241 let interface = self.read_recursive();
1242 if false {
1243 eprintln!("[warning] sanity check disabled for dual_module.rs");
1244 return Ok(flattened_nodes);
1245 }
1246 let mut visited_syndrome = HashSet::with_capacity((interface.nodes_count() * 2) as usize);
1247 let mut sum_individual_dual_variable = 0;
1248 for (index, dual_node_ptr) in flattened_nodes.iter().enumerate() {
1249 if let Some(dual_node_ptr) = dual_node_ptr {
1250 let dual_node = dual_node_ptr.read_recursive();
1251 sum_individual_dual_variable += dual_node.get_dual_variable(&interface);
1252 if dual_node.index != index as NodeIndex {
1253 return Err(format!(
1254 "dual node index wrong: expected {}, actual {}",
1255 index, dual_node.index
1256 ));
1257 }
1258 match &dual_node.class {
1259 DualNodeClass::Blossom {
1260 nodes_circle,
1261 touching_children,
1262 } => {
1263 for (idx, circle_node_weak) in nodes_circle.iter().enumerate() {
1264 let circle_node_ptr = circle_node_weak.upgrade_force();
1265 if &circle_node_ptr == dual_node_ptr {
1266 return Err("a blossom should not contain itself".to_string());
1267 }
1268 let circle_node = circle_node_ptr.read_recursive();
1269 if circle_node.parent_blossom.as_ref() != Some(&dual_node_ptr.downgrade()) {
1270 return Err(format!(
1271 "blossom {} contains {} but child's parent pointer = {:?} is not pointing back",
1272 dual_node.index, circle_node.index, circle_node.parent_blossom
1273 ));
1274 }
1275 if circle_node.grow_state != DualNodeGrowState::Stay {
1276 return Err(format!("child node {} is not at Stay state", circle_node.index));
1277 }
1278 if circle_node.index >= interface.nodes_count()
1280 || interface.get_node(circle_node.index).is_none()
1281 {
1282 return Err(format!("child's index {} is not in the interface", circle_node.index));
1283 }
1284 let tracked_circle_node_ptr = interface.get_node(circle_node.index).unwrap();
1285 if tracked_circle_node_ptr != circle_node_ptr {
1286 return Err(format!(
1287 "the tracked ptr of child {} is not what's being pointed",
1288 circle_node.index
1289 ));
1290 }
1291 let (child_weak_1, child_weak_2) = &touching_children[idx];
1293 if matches!(circle_node.class, DualNodeClass::DefectVertex { .. }) {
1294 if child_weak_1 != circle_node_weak {
1295 return Err(format!("touching child can only be syndrome node {}", circle_node.index));
1296 }
1297 if child_weak_2 != circle_node_weak {
1298 return Err(format!("touching child can only be syndrome node {}", circle_node.index));
1299 }
1300 } else {
1301 let child_ptr_1 = child_weak_1.upgrade_force();
1302 let child_ptr_2 = child_weak_2.upgrade_force();
1303 let child_1_ancestor = child_ptr_1.get_ancestor_blossom();
1304 let child_2_ancestor = child_ptr_2.get_ancestor_blossom();
1305 let circle_ancestor = circle_node_ptr.get_ancestor_blossom();
1306 if child_1_ancestor != circle_ancestor {
1307 return Err(format!("{:?} is not descendent of {}", child_ptr_1, circle_node.index));
1308 }
1309 if child_2_ancestor != circle_ancestor {
1310 return Err(format!("{:?} is not descendent of {}", child_ptr_2, circle_node.index));
1311 }
1312 }
1313 }
1314 }
1315 DualNodeClass::DefectVertex { defect_index } => {
1316 if visited_syndrome.contains(defect_index) {
1317 return Err(format!("duplicate defect index: {}", defect_index));
1318 }
1319 visited_syndrome.insert(*defect_index);
1320 }
1321 }
1322 if let Some(parent_blossom_weak) = &dual_node.parent_blossom {
1323 if dual_node.grow_state != DualNodeGrowState::Stay {
1324 return Err(format!("child node {} is not at Stay state", dual_node.index));
1325 }
1326 let parent_blossom_ptr = parent_blossom_weak.upgrade_force();
1327 let parent_blossom = parent_blossom_ptr.read_recursive();
1328 match &parent_blossom.class {
1330 DualNodeClass::Blossom { nodes_circle, .. } => {
1331 let mut found_match_count = 0;
1332 for node_weak in nodes_circle.iter() {
1333 let node_ptr = node_weak.upgrade_force();
1334 if &node_ptr == dual_node_ptr {
1335 found_match_count += 1;
1336 }
1337 }
1338 if found_match_count != 1 {
1339 return Err(format!(
1340 "{} is the parent of {} but the child only presents {} times",
1341 parent_blossom.index, dual_node.index, found_match_count
1342 ));
1343 }
1344 }
1345 _ => {
1346 return Err(format!(
1347 "{}, as the parent of {}, is not a blossom",
1348 parent_blossom.index, dual_node.index
1349 ))
1350 }
1351 }
1352 if parent_blossom.index >= interface.nodes_count() || interface.get_node(parent_blossom.index).is_none()
1354 {
1355 return Err(format!(
1356 "parent blossom's index {} is not in the interface",
1357 parent_blossom.index
1358 ));
1359 }
1360 let tracked_parent_blossom_ptr = interface.get_node(parent_blossom.index).unwrap();
1361 if tracked_parent_blossom_ptr != parent_blossom_ptr {
1362 return Err(format!(
1363 "the tracked ptr of parent blossom {} is not what's being pointed",
1364 parent_blossom.index
1365 ));
1366 }
1367 }
1368 }
1369 }
1370 if sum_individual_dual_variable != interface.sum_dual_variables {
1371 return Err(format!(
1372 "internal error: the sum of dual variables is {} but individual sum is {}",
1373 interface.sum_dual_variables, sum_individual_dual_variable
1374 ));
1375 }
1376 Ok(flattened_nodes)
1377 }
1378
1379 pub fn sum_dual_variables(&self) -> Weight {
1380 self.read_recursive().sum_dual_variables
1381 }
1382}
1383
1384impl Ord for MaxUpdateLength {
1385 fn cmp(&self, other: &Self) -> Ordering {
1386 debug_assert!(
1387 !matches!(self, MaxUpdateLength::NonZeroGrow(_)),
1388 "priority ordering is not valid for NonZeroGrow"
1389 );
1390 debug_assert!(
1391 !matches!(other, MaxUpdateLength::NonZeroGrow(_)),
1392 "priority ordering is not valid for NonZeroGrow"
1393 );
1394 if self == other {
1395 return Ordering::Equal;
1396 }
1397 match (
1403 matches!(self, MaxUpdateLength::VertexShrinkStop(..)),
1404 matches!(other, MaxUpdateLength::VertexShrinkStop(..)),
1405 ) {
1406 (true, false) => return Ordering::Less, (false, true) => return Ordering::Greater, (true, true) => {
1409 return self
1410 .get_vertex_shrink_stop()
1411 .unwrap()
1412 .cmp(&other.get_vertex_shrink_stop().unwrap())
1413 } _ => {}
1415 }
1416 match (
1418 matches!(self, MaxUpdateLength::BlossomNeedExpand(..)),
1419 matches!(other, MaxUpdateLength::BlossomNeedExpand(..)),
1420 ) {
1421 (true, false) => return Ordering::Less, (false, true) => return Ordering::Greater, (true, true) => {
1424 return self
1425 .get_blossom_need_expand()
1426 .unwrap()
1427 .cmp(&other.get_blossom_need_expand().unwrap())
1428 } _ => {}
1430 }
1431 match (
1434 matches!(self, MaxUpdateLength::TouchingVirtual(..)),
1435 matches!(other, MaxUpdateLength::TouchingVirtual(..)),
1436 ) {
1437 (true, false) => return Ordering::Less, (false, true) => return Ordering::Greater, (true, true) => {
1440 let (a, c) = self.get_touching_virtual().unwrap();
1441 let (b, d) = other.get_touching_virtual().unwrap();
1442 return a.cmp(&b).reverse().then(c.cmp(&d).reverse());
1443 } _ => {}
1445 }
1446 let (a, c) = self.get_conflicting().unwrap();
1448 let (b, d) = other.get_conflicting().unwrap();
1449 a.cmp(&b).reverse().then(c.cmp(&d).reverse())
1450 }
1451}
1452
1453impl PartialOrd for MaxUpdateLength {
1454 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1455 Some(self.cmp(other))
1456 }
1457}
1458
1459impl MaxUpdateLength {
1460 pub fn update(&self) {
1462 match self {
1463 Self::NonZeroGrow(_) => {}
1464 Self::Conflicting((a, b), (c, d)) => {
1465 for x in [a, b, c, d] {
1466 x.update();
1467 }
1468 }
1469 Self::TouchingVirtual((a, b), _) => {
1470 for x in [a, b] {
1471 x.update();
1472 }
1473 }
1474 Self::BlossomNeedExpand(x) => {
1475 x.update();
1476 }
1477 Self::VertexShrinkStop((a, option)) => {
1478 a.update();
1479 if let Some((b, c)) = option {
1480 b.update();
1481 c.update();
1482 }
1483 }
1484 }
1485 }
1486
1487 #[allow(dead_code)]
1489 pub fn is_conflicting(&self, a: &DualNodePtr, b: &DualNodePtr) -> bool {
1490 if let MaxUpdateLength::Conflicting((n1, _), (n2, _)) = self {
1491 if n1 == a && n2 == b {
1492 return true;
1493 }
1494 if n1 == b && n2 == a {
1495 return true;
1496 }
1497 }
1498 false
1499 }
1500
1501 #[allow(dead_code)]
1503 #[inline(always)]
1504 pub fn get_none_zero_growth(&self) -> Option<Weight> {
1505 match self {
1506 Self::NonZeroGrow((length, _has_empty_boundary_node)) => Some(*length),
1507 _ => None,
1508 }
1509 }
1510
1511 #[allow(dead_code)]
1513 #[inline(always)]
1514 pub fn get_conflicting(&self) -> Option<(DualNodePtr, DualNodePtr)> {
1515 match self {
1516 Self::Conflicting((a, _), (b, _)) => Some((a.clone(), b.clone())),
1517 _ => None,
1518 }
1519 }
1520
1521 #[allow(dead_code)]
1523 #[inline(always)]
1524 pub fn get_touching_virtual(&self) -> Option<(DualNodePtr, VertexIndex)> {
1525 match self {
1526 Self::TouchingVirtual((a, _), (b, _)) => Some((a.clone(), *b)),
1527 _ => None,
1528 }
1529 }
1530
1531 #[allow(dead_code)]
1533 #[inline(always)]
1534 pub fn get_blossom_need_expand(&self) -> Option<DualNodePtr> {
1535 match self {
1536 Self::BlossomNeedExpand(a) => Some(a.clone()),
1537 _ => None,
1538 }
1539 }
1540
1541 #[allow(dead_code)]
1543 #[inline(always)]
1544 pub fn get_vertex_shrink_stop(&self) -> Option<DualNodePtr> {
1545 match self {
1546 Self::VertexShrinkStop((a, _)) => Some(a.clone()),
1547 _ => None,
1548 }
1549 }
1550}
1551
1552#[derive(Debug, Clone)]
1554pub struct EdgeWeightModifier {
1555 pub modified: Vec<(EdgeIndex, Weight)>,
1557}
1558
1559impl Default for EdgeWeightModifier {
1560 fn default() -> Self {
1561 Self::new()
1562 }
1563}
1564
1565impl EdgeWeightModifier {
1566 pub fn new() -> Self {
1567 Self { modified: vec![] }
1568 }
1569
1570 pub fn push_modified_edge(&mut self, erasure_edge: EdgeIndex, original_weight: Weight) {
1572 self.modified.push((erasure_edge, original_weight));
1573 }
1574
1575 pub fn has_modified_edges(&self) -> bool {
1577 !self.modified.is_empty()
1578 }
1579
1580 pub fn pop_modified_edge(&mut self) -> (EdgeIndex, Weight) {
1582 self.modified
1583 .pop()
1584 .expect("no more modified edges, please check `has_modified_edges` before calling this method")
1585 }
1586}
1587
1588impl std::ops::Deref for EdgeWeightModifier {
1589 type Target = Vec<(EdgeIndex, Weight)>;
1590
1591 fn deref(&self) -> &Self::Target {
1592 &self.modified
1593 }
1594}