fusion_blossom/
primal_module_serial.rs

1//! Serial Primal Module
2//!
3//! A serial implementation of the primal module. This is the very basic fusion blossom algorithm that aims at debugging and as a ground truth
4//! where traditional matching is too time-consuming because of their |E| = O(|V|^2) scaling.
5//!
6
7#![cfg_attr(feature = "unsafe_pointer", allow(dropping_references))]
8
9use std::cmp::Ordering;
10use std::num::NonZeroUsize;
11
12use crate::derivative::Derivative;
13
14use super::dual_module::*;
15use super::pointers::*;
16use super::primal_module::*;
17use super::util::*;
18use super::visualize::*;
19
20#[derive(Derivative)]
21#[derivative(Debug)]
22pub struct PrimalModuleSerial {
23    /// unit index of this interface, default to 0
24    pub unit_index: usize,
25    /// nodes internal information
26    pub nodes: Vec<Option<PrimalNodeInternalPtr>>,
27    /// current nodes length, to enable constant-time clear operation
28    pub nodes_length: usize,
29    /// allow pointer reuse will reduce the time of reallocation, but it's unsafe if not owning it
30    pub is_fusion: bool,
31    /// the indices of primal nodes that is possibly matched to the mirrored vertex, and need to break when mirrored vertices are no longer mirrored
32    pub possible_break: Vec<NodeIndex>,
33    /// debug mode: only resolve one conflict each time
34    pub debug_resolve_only_one: bool,
35    /// the parent of this serial module, when fused
36    pub parent: Option<PrimalModuleSerialWeak>,
37    /// when fused, this will indicate the relative bias given by the parent
38    pub index_bias: NodeIndex,
39    /// the two children of this serial module, when fused; following the length of this child,
40    /// given that fused children serial modules will not have new nodes anymore
41    pub children: Option<((PrimalModuleSerialWeak, NodeNum), (PrimalModuleSerialWeak, NodeNum))>,
42    /// the maximum number of children in a tree before it collapses to a union-find decoder
43    pub max_tree_size: usize,
44}
45
46pub type PrimalModuleSerialPtr = ArcManualSafeLock<PrimalModuleSerial>;
47pub type PrimalModuleSerialWeak = WeakManualSafeLock<PrimalModuleSerial>;
48
49impl std::fmt::Debug for PrimalModuleSerialPtr {
50    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
51        let interface = self.read_recursive();
52        write!(f, "{}", interface.unit_index)
53    }
54}
55
56impl std::fmt::Debug for PrimalModuleSerialWeak {
57    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
58        self.upgrade_force().fmt(f)
59    }
60}
61
62#[derive(Derivative)]
63#[derivative(Debug)]
64pub struct AlternatingTreeNode {
65    /// the root of an alternating tree
66    pub root: PrimalNodeInternalWeak,
67    /// the parent in the alternating tree, note that root doesn't have a parent; together with a child of blossom that touches parent, used to create blossom and expand perfect matching
68    pub parent: Option<(PrimalNodeInternalWeak, DualNodeWeak)>,
69    /// the children in the alternating tree, note that odd depth can only have exactly one child; together with a child of blossom that touches each child node in the tree, used to create blossom and expand perfect matching
70    pub children: Vec<(PrimalNodeInternalWeak, DualNodeWeak)>,
71    /// the depth in the alternating tree, root has 0 depth
72    pub depth: usize,
73    /// the number of children in the tree; only the root has this variable.
74    pub tree_size: Option<NonZeroUsize>,
75}
76
77#[derive(Debug, Clone, PartialEq, Eq)]
78pub enum MatchTarget {
79    Peer(PrimalNodeInternalWeak),
80    VirtualVertex(VertexIndex),
81}
82
83/// internal information of the primal node, added to the [`DualNode`]; note that primal nodes and dual nodes
84/// always have one-to-one correspondence
85#[derive(Derivative)]
86#[derivative(Debug)]
87pub struct PrimalNodeInternal {
88    /// the pointer to the origin [`DualNode`]
89    pub origin: DualNodeWeak,
90    /// local index, to find myself in [`DualModuleSerial::nodes`]
91    pub index: NodeIndex,
92    /// alternating tree information if applicable
93    pub tree_node: Option<AlternatingTreeNode>,
94    /// temporary match with another node, (target, touching_grandson)
95    pub temporary_match: Option<(MatchTarget, DualNodeWeak)>,
96    /// belonging of the dual module interface; a dual node is never standalone
97    pub belonging: PrimalModuleSerialWeak,
98}
99
100pub type PrimalNodeInternalPtr = ArcManualSafeLock<PrimalNodeInternal>;
101pub type PrimalNodeInternalWeak = WeakManualSafeLock<PrimalNodeInternal>;
102
103impl std::fmt::Debug for PrimalNodeInternalPtr {
104    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
105        self.update(); // to make sure index is up-to-date
106        let primal_node_internal = self.read_recursive();
107        write!(f, "{}", primal_node_internal.index)
108    }
109}
110
111impl std::fmt::Debug for PrimalNodeInternalWeak {
112    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
113        self.upgrade_force().fmt(f)
114    }
115}
116
117impl PrimalNodeInternal {
118    /// check if in the cache, this node is a free node
119    pub fn is_free(&self) -> bool {
120        debug_assert!(
121            {
122                let origin_ptr = self.origin.upgrade_force();
123                let node = origin_ptr.read_recursive();
124                node.parent_blossom.is_none()
125            },
126            "do not call this function to a internal node, consider call PrimalModuleSerial::get_outer_node"
127        );
128        if self.tree_node.is_some() {
129            return false;
130        } // this node belongs to an alternating tree
131        if self.temporary_match.is_some() {
132            return false;
133        } // already temporarily matched
134        true
135    }
136
137    /// modify the depth and root of a sub-tree using DFS
138    pub fn change_sub_tree_root(&mut self, depth: usize, root: PrimalNodeInternalPtr) {
139        let tree_node = self.tree_node.as_mut().unwrap();
140        tree_node.depth = depth;
141        tree_node.root = root.downgrade();
142        for (child_weak, _) in tree_node.children.iter() {
143            let child_ptr = child_weak.upgrade_force();
144            lock_write!(child, child_ptr);
145            child.change_sub_tree_root(depth + 1, root.clone());
146        }
147    }
148}
149
150impl PrimalNodeInternalPtr {
151    /// when fused, primal node may be outdated; refresh here
152    pub fn update(&self) -> &Self {
153        let mut current_belonging = self.read_recursive().belonging.upgrade_force();
154        let mut bias = 0;
155        let mut node = self.write();
156        while current_belonging.read_recursive().parent.is_some() {
157            let belonging_module = current_belonging.read_recursive();
158            bias += belonging_module.index_bias;
159            let new_current_belonging = belonging_module.parent.clone().unwrap().upgrade_force();
160            drop(belonging_module);
161            current_belonging = new_current_belonging;
162        }
163        node.belonging = current_belonging.downgrade();
164        node.index += bias;
165        self
166    }
167}
168
169impl PrimalModuleImpl for PrimalModuleSerialPtr {
170    fn new_empty(_initializer: &SolverInitializer) -> Self {
171        Self::new_value(PrimalModuleSerial {
172            unit_index: 0, // if necessary, manually change it
173            nodes: vec![],
174            nodes_length: 0,
175            is_fusion: false,
176            possible_break: vec![],
177            debug_resolve_only_one: false,
178            parent: None,
179            index_bias: 0,
180            children: None,
181            // // Union-Find
182            // max_tree_size: 0,
183            // Minimum Weight Perfect Matching
184            max_tree_size: usize::MAX,
185        })
186    }
187
188    fn clear(&mut self) {
189        let mut module = self.write();
190        module.nodes_length = 0; // without actually dropping all the nodes, to enable constant time clear
191        module.possible_break.clear();
192        module.is_fusion = false;
193        module.parent = None;
194        module.index_bias = 0;
195        module.children = None;
196    }
197
198    fn load_defect_dual_node(&mut self, dual_node_ptr: &DualNodePtr) {
199        let belonging = self.downgrade();
200        let node = dual_node_ptr.read_recursive();
201        debug_assert!(
202            matches!(node.class, DualNodeClass::DefectVertex { .. }),
203            "must load a fresh dual module interface, found a blossom"
204        );
205        let mut module = self.write();
206        let local_node_index = module.nodes_length;
207        let node_index = module.nodes_count();
208        debug_assert_eq!(node.index, node_index, "must load in order");
209        let primal_node_internal_ptr =
210            if !module.is_fusion && local_node_index < module.nodes.len() && module.nodes[local_node_index].is_some() {
211                let node_ptr = module.nodes[local_node_index].take().unwrap();
212                let mut node = node_ptr.write();
213                node.origin = dual_node_ptr.downgrade();
214                node.index = node_index;
215                node.tree_node = None;
216                node.temporary_match = None;
217                node.belonging = belonging;
218                drop(node);
219                node_ptr
220            } else {
221                PrimalNodeInternalPtr::new_value(PrimalNodeInternal {
222                    origin: dual_node_ptr.downgrade(),
223                    index: node_index,
224                    tree_node: None,
225                    temporary_match: None,
226                    belonging,
227                })
228            };
229        module.nodes_length += 1;
230        if module.nodes.len() < module.nodes_length {
231            module.nodes.push(None);
232        }
233        module.nodes[local_node_index] = Some(primal_node_internal_ptr);
234    }
235
236    #[allow(clippy::collapsible_else_if)]
237    fn resolve<D: DualModuleImpl>(
238        &mut self,
239        mut group_max_update_length: GroupMaxUpdateLength,
240        interface_ptr: &DualModuleInterfacePtr,
241        dual_module: &mut D,
242    ) {
243        debug_assert!(!group_max_update_length.is_empty() && group_max_update_length.get_none_zero_growth().is_none());
244        let mut current_conflict_index = 0;
245        let debug_resolve_only_one = self.read_recursive().debug_resolve_only_one;
246        let max_tree_size = self.read_recursive().max_tree_size;
247        while let Some(conflict) = group_max_update_length.pop() {
248            current_conflict_index += 1;
249            if debug_resolve_only_one && current_conflict_index > 1 {
250                // debug mode
251                break;
252            }
253            // println!("conflict: {conflict:?}");
254            match conflict {
255                MaxUpdateLength::Conflicting((node_ptr_1, touching_ptr_1), (node_ptr_2, touching_ptr_2)) => {
256                    debug_assert!(
257                        node_ptr_1 != node_ptr_2,
258                        "one cannot conflict with itself, double check to avoid deadlock"
259                    );
260                    if self.get_primal_node_internal_ptr_option(&node_ptr_1).is_none() {
261                        continue;
262                    } // ignore out-of-date event
263                    if self.get_primal_node_internal_ptr_option(&node_ptr_2).is_none() {
264                        continue;
265                    } // ignore out-of-date event
266                      // always use outer node in case it's already wrapped into a blossom
267                    let primal_node_internal_ptr_1 = self.get_outer_node(self.get_primal_node_internal_ptr(&node_ptr_1));
268                    let primal_node_internal_ptr_2 = self.get_outer_node(self.get_primal_node_internal_ptr(&node_ptr_2));
269                    if primal_node_internal_ptr_1 == primal_node_internal_ptr_2 {
270                        debug_assert!(
271                            current_conflict_index != 1,
272                            "the first conflict cannot be ignored, otherwise may cause hidden infinite loop"
273                        );
274                        continue; // this is no longer a conflict because both of them belongs to a single blossom
275                    }
276                    let mut primal_node_internal_1 = primal_node_internal_ptr_1.write();
277                    let mut primal_node_internal_2 = primal_node_internal_ptr_2.write();
278                    let grow_state_1 = primal_node_internal_1.origin.upgrade_force().read_recursive().grow_state;
279                    let grow_state_2 = primal_node_internal_2.origin.upgrade_force().read_recursive().grow_state;
280                    if !grow_state_1.is_against(&grow_state_2) {
281                        debug_assert!(
282                            current_conflict_index != 1,
283                            "the first conflict cannot be ignored, otherwise may cause hidden infinite loop"
284                        );
285                        continue; // this is no longer a conflict
286                    }
287                    // this is the most probable case, so put it in the front
288                    let (free_1, free_2) = (primal_node_internal_1.is_free(), primal_node_internal_2.is_free());
289                    if free_1 && free_2 {
290                        // simply match them temporarily
291                        primal_node_internal_1.temporary_match = Some((
292                            MatchTarget::Peer(primal_node_internal_ptr_2.downgrade()),
293                            touching_ptr_1.downgrade(),
294                        ));
295                        primal_node_internal_2.temporary_match = Some((
296                            MatchTarget::Peer(primal_node_internal_ptr_1.downgrade()),
297                            touching_ptr_2.downgrade(),
298                        ));
299                        // update dual module interface
300                        interface_ptr.set_grow_state(
301                            &primal_node_internal_1.origin.upgrade_force(),
302                            DualNodeGrowState::Stay,
303                            dual_module,
304                        );
305                        interface_ptr.set_grow_state(
306                            &primal_node_internal_2.origin.upgrade_force(),
307                            DualNodeGrowState::Stay,
308                            dual_module,
309                        );
310                        continue;
311                    }
312                    // second probable case: single node touches a temporary matched pair and become an alternating tree
313                    if (free_1 && primal_node_internal_2.temporary_match.is_some())
314                        || (free_2 && primal_node_internal_1.temporary_match.is_some())
315                    {
316                        let (
317                            free_node_internal_ptr,
318                            free_touching_ptr,
319                            mut free_node_internal,
320                            matched_node_internal_ptr,
321                            matched_touching_ptr,
322                            mut matched_node_internal,
323                        ) = if free_1 {
324                            (
325                                primal_node_internal_ptr_1.clone(),
326                                touching_ptr_1.clone(),
327                                primal_node_internal_1,
328                                primal_node_internal_ptr_2.clone(),
329                                touching_ptr_2.clone(),
330                                primal_node_internal_2,
331                            )
332                        } else {
333                            (
334                                primal_node_internal_ptr_2.clone(),
335                                touching_ptr_2.clone(),
336                                primal_node_internal_2,
337                                primal_node_internal_ptr_1.clone(),
338                                touching_ptr_1.clone(),
339                                primal_node_internal_1,
340                            )
341                        };
342                        // creating an alternating tree: free node becomes the root, matched node becomes child
343                        let (match_target, matched_touching_grandson) =
344                            matched_node_internal.temporary_match.as_ref().unwrap().clone();
345                        match &match_target {
346                            MatchTarget::Peer(leaf_node_internal_weak) => {
347                                let leaf_node_internal_ptr = leaf_node_internal_weak.upgrade_force();
348                                let mut leaf_node_internal = leaf_node_internal_ptr.write();
349                                let mut tree_size = free_node_internal.origin.upgrade_force().read_recursive().defect_size;
350                                tree_size = tree_size.saturating_add(
351                                    matched_node_internal
352                                        .origin
353                                        .upgrade_force()
354                                        .read_recursive()
355                                        .defect_size
356                                        .get(),
357                                );
358                                tree_size = tree_size.saturating_add(
359                                    leaf_node_internal.origin.upgrade_force().read_recursive().defect_size.get(),
360                                );
361                                free_node_internal.tree_node = Some(AlternatingTreeNode {
362                                    root: free_node_internal_ptr.downgrade(),
363                                    parent: None,
364                                    children: vec![(matched_node_internal_ptr.downgrade(), free_touching_ptr.downgrade())],
365                                    depth: 0,
366                                    tree_size: Some(tree_size),
367                                });
368                                matched_node_internal.tree_node = Some(AlternatingTreeNode {
369                                    root: free_node_internal_ptr.downgrade(),
370                                    parent: Some((free_node_internal_ptr.downgrade(), matched_touching_ptr.downgrade())),
371                                    children: vec![(leaf_node_internal_weak.clone(), matched_touching_grandson)],
372                                    depth: 1,
373                                    tree_size: None, // not root
374                                });
375                                matched_node_internal.temporary_match = None;
376                                leaf_node_internal.tree_node = Some(AlternatingTreeNode {
377                                    root: free_node_internal_ptr.downgrade(),
378                                    parent: Some((
379                                        matched_node_internal_ptr.downgrade(),
380                                        leaf_node_internal.temporary_match.as_ref().unwrap().1.clone(),
381                                    )),
382                                    children: vec![],
383                                    depth: 2,
384                                    tree_size: None, // not root
385                                });
386                                leaf_node_internal.temporary_match = None;
387                                // update dual module interface
388                                if tree_size.get() > max_tree_size {
389                                    drop(free_node_internal);
390                                    drop(matched_node_internal);
391                                    drop(leaf_node_internal);
392                                    self.collapse_tree(free_node_internal_ptr, interface_ptr, dual_module);
393                                } else {
394                                    interface_ptr.set_grow_state(
395                                        &free_node_internal.origin.upgrade_force(),
396                                        DualNodeGrowState::Grow,
397                                        dual_module,
398                                    );
399                                    interface_ptr.set_grow_state(
400                                        &matched_node_internal.origin.upgrade_force(),
401                                        DualNodeGrowState::Shrink,
402                                        dual_module,
403                                    );
404                                    interface_ptr.set_grow_state(
405                                        &leaf_node_internal.origin.upgrade_force(),
406                                        DualNodeGrowState::Grow,
407                                        dual_module,
408                                    );
409                                }
410                                continue;
411                            }
412                            MatchTarget::VirtualVertex(_) => {
413                                // virtual boundary doesn't have to be matched, so in this case simply match these two nodes together
414                                free_node_internal.temporary_match = Some((
415                                    MatchTarget::Peer(matched_node_internal_ptr.downgrade()),
416                                    free_touching_ptr.downgrade(),
417                                ));
418                                matched_node_internal.temporary_match = Some((
419                                    MatchTarget::Peer(free_node_internal_ptr.downgrade()),
420                                    matched_touching_ptr.downgrade(),
421                                ));
422                                // update dual module interface
423                                interface_ptr.set_grow_state(
424                                    &free_node_internal.origin.upgrade_force(),
425                                    DualNodeGrowState::Stay,
426                                    dual_module,
427                                );
428                                interface_ptr.set_grow_state(
429                                    &matched_node_internal.origin.upgrade_force(),
430                                    DualNodeGrowState::Stay,
431                                    dual_module,
432                                );
433                                continue;
434                            }
435                        }
436                    }
437                    // third probable case: tree touches single vertex
438                    if (free_1 && primal_node_internal_2.tree_node.is_some())
439                        || (primal_node_internal_1.tree_node.is_some() && free_2)
440                    {
441                        let (
442                            tree_node_internal_ptr,
443                            tree_touching_ptr,
444                            tree_node_internal,
445                            free_node_internal_ptr,
446                            free_touching_ptr,
447                            mut free_node_internal,
448                        ) = if primal_node_internal_1.tree_node.is_some() {
449                            (
450                                primal_node_internal_ptr_1.clone(),
451                                touching_ptr_1.clone(),
452                                primal_node_internal_1,
453                                primal_node_internal_ptr_2.clone(),
454                                touching_ptr_2.clone(),
455                                primal_node_internal_2,
456                            )
457                        } else {
458                            (
459                                primal_node_internal_ptr_2.clone(),
460                                touching_ptr_2.clone(),
461                                primal_node_internal_2,
462                                primal_node_internal_ptr_1.clone(),
463                                touching_ptr_1.clone(),
464                                primal_node_internal_1,
465                            )
466                        };
467                        free_node_internal.temporary_match = Some((
468                            MatchTarget::Peer(tree_node_internal_ptr.downgrade()),
469                            free_touching_ptr.downgrade(),
470                        ));
471                        interface_ptr.set_grow_state(
472                            &free_node_internal.origin.upgrade_force(),
473                            DualNodeGrowState::Stay,
474                            dual_module,
475                        );
476                        drop(tree_node_internal); // unlock
477                        Self::augment_tree_given_matched(
478                            tree_node_internal_ptr,
479                            free_node_internal_ptr,
480                            tree_touching_ptr.downgrade(),
481                            interface_ptr,
482                            dual_module,
483                        );
484                        continue;
485                    }
486                    // fourth probable case: tree touches matched pair
487                    if (primal_node_internal_1.tree_node.is_some() && primal_node_internal_2.temporary_match.is_some())
488                        || (primal_node_internal_1.temporary_match.is_some() && primal_node_internal_2.tree_node.is_some())
489                    {
490                        let (
491                            tree_node_internal_ptr,
492                            tree_touching_ptr,
493                            mut tree_node_internal,
494                            matched_node_internal_ptr,
495                            matched_touching_ptr,
496                            mut matched_node_internal,
497                        ) = if primal_node_internal_1.tree_node.is_some() {
498                            (
499                                primal_node_internal_ptr_1.clone(),
500                                touching_ptr_1.clone(),
501                                primal_node_internal_1,
502                                primal_node_internal_ptr_2.clone(),
503                                touching_ptr_2.clone(),
504                                primal_node_internal_2,
505                            )
506                        } else {
507                            (
508                                primal_node_internal_ptr_2.clone(),
509                                touching_ptr_2.clone(),
510                                primal_node_internal_2,
511                                primal_node_internal_ptr_1.clone(),
512                                touching_ptr_1.clone(),
513                                primal_node_internal_1,
514                            )
515                        };
516                        let match_target = matched_node_internal.temporary_match.as_ref().unwrap().0.clone();
517                        match &match_target {
518                            MatchTarget::Peer(leaf_node_internal_weak) => {
519                                let leaf_node_internal_ptr = leaf_node_internal_weak.upgrade_force();
520                                let tree_node = tree_node_internal.tree_node.as_mut().unwrap();
521                                debug_assert!(tree_node.depth % 2 == 0, "conflicting one must be + node");
522                                // simply add this matched pair to the children
523                                tree_node
524                                    .children
525                                    .push((matched_node_internal_ptr.downgrade(), tree_touching_ptr.downgrade()));
526                                // link children to parent
527                                matched_node_internal.tree_node = Some(AlternatingTreeNode {
528                                    root: tree_node.root.clone(),
529                                    parent: Some((tree_node_internal_ptr.downgrade(), matched_touching_ptr.downgrade())),
530                                    children: vec![(
531                                        leaf_node_internal_weak.clone(),
532                                        matched_node_internal.temporary_match.as_ref().unwrap().1.clone(),
533                                    )],
534                                    depth: tree_node.depth + 1,
535                                    tree_size: None,
536                                });
537                                matched_node_internal.temporary_match = None;
538                                let mut leaf_node_internal = leaf_node_internal_ptr.write();
539                                leaf_node_internal.tree_node = Some(AlternatingTreeNode {
540                                    root: tree_node.root.clone(),
541                                    parent: Some((
542                                        matched_node_internal_ptr.downgrade(),
543                                        leaf_node_internal.temporary_match.as_ref().unwrap().1.clone(),
544                                    )),
545                                    children: vec![],
546                                    depth: tree_node.depth + 2,
547                                    tree_size: None,
548                                });
549                                leaf_node_internal.temporary_match = None;
550                                // update the tree size (root might be tree_node, so drop them first)
551                                let root_node_ptr = &tree_node.root.clone().upgrade_force();
552                                drop(tree_node_internal);
553                                let mut root_node = root_node_ptr.write();
554                                let root_tree_node = root_node.tree_node.as_mut().unwrap();
555                                let mut tree_size = *root_tree_node.tree_size.as_ref().unwrap();
556                                tree_size = tree_size.saturating_add(
557                                    matched_node_internal
558                                        .origin
559                                        .upgrade_force()
560                                        .read_recursive()
561                                        .defect_size
562                                        .get(),
563                                );
564                                tree_size = tree_size.saturating_add(
565                                    leaf_node_internal.origin.upgrade_force().read_recursive().defect_size.get(),
566                                );
567                                root_tree_node.tree_size = Some(tree_size);
568                                // update dual module interface
569                                if tree_size.get() > max_tree_size {
570                                    drop(matched_node_internal);
571                                    drop(leaf_node_internal);
572                                    self.collapse_tree(root_node_ptr.clone(), interface_ptr, dual_module);
573                                } else {
574                                    interface_ptr.set_grow_state(
575                                        &matched_node_internal.origin.upgrade_force(),
576                                        DualNodeGrowState::Shrink,
577                                        dual_module,
578                                    );
579                                    interface_ptr.set_grow_state(
580                                        &leaf_node_internal.origin.upgrade_force(),
581                                        DualNodeGrowState::Grow,
582                                        dual_module,
583                                    );
584                                }
585                                continue;
586                            }
587                            MatchTarget::VirtualVertex(_) => {
588                                // virtual boundary doesn't have to be matched, so in this case remove it and augment the tree
589                                matched_node_internal.temporary_match = Some((
590                                    MatchTarget::Peer(tree_node_internal_ptr.downgrade()),
591                                    matched_touching_ptr.downgrade(),
592                                ));
593                                drop(matched_node_internal); // unlock
594                                drop(tree_node_internal); // unlock
595                                Self::augment_tree_given_matched(
596                                    tree_node_internal_ptr,
597                                    matched_node_internal_ptr,
598                                    tree_touching_ptr.downgrade(),
599                                    interface_ptr,
600                                    dual_module,
601                                );
602                                continue;
603                            }
604                        }
605                    }
606                    // much less probable case: two trees touch and both are augmented
607                    if primal_node_internal_1.tree_node.is_some() && primal_node_internal_2.tree_node.is_some() {
608                        let root_1 = primal_node_internal_1.tree_node.as_ref().unwrap().root.clone();
609                        let root_2 = primal_node_internal_2.tree_node.as_ref().unwrap().root.clone();
610                        // form a blossom inside an alternating tree
611                        if root_1 == root_2 {
612                            // drop writer lock to allow reader locks
613                            let root_weak = primal_node_internal_1.tree_node.as_ref().unwrap().root.clone();
614                            drop(primal_node_internal_1);
615                            drop(primal_node_internal_2);
616                            let tree_size = {
617                                let root_ptr = root_weak.upgrade_force();
618                                let tree_size = root_ptr.read_recursive().tree_node.as_ref().unwrap().tree_size;
619                                tree_size.unwrap()
620                            };
621                            // find LCA of two nodes, two paths are from child to parent
622                            let (lca_ptr, path_1, path_2) = self.find_lowest_common_ancestor(
623                                primal_node_internal_ptr_1.clone(),
624                                primal_node_internal_ptr_2.clone(),
625                            );
626                            let nodes_circle = {
627                                let mut nodes_circle: Vec<DualNodePtr> =
628                                    path_1.iter().map(|ptr| ptr.read_recursive().origin.upgrade_force()).collect();
629                                nodes_circle.push(lca_ptr.read_recursive().origin.upgrade_force());
630                                for i in (0..path_2.len()).rev() {
631                                    nodes_circle.push(path_2[i].read_recursive().origin.upgrade_force());
632                                }
633                                nodes_circle
634                            };
635                            // build `touching_children`
636                            let touching_children = {
637                                let mut touching_children = Vec::<(DualNodeWeak, DualNodeWeak)>::new();
638                                if !path_1.is_empty() {
639                                    for (idx, ptr) in path_1.iter().enumerate() {
640                                        let node = ptr.read_recursive();
641                                        let tree_node = node.tree_node.as_ref().unwrap();
642                                        let left_touching_ptr = if idx == 0 {
643                                            touching_ptr_1.downgrade()
644                                        } else {
645                                            let last_ptr = path_1[idx - 1].downgrade();
646                                            let idx = tree_node
647                                                .children
648                                                .iter()
649                                                .position(|(ptr, _)| ptr == &last_ptr)
650                                                .expect("should find child");
651                                            tree_node.children[idx].1.clone()
652                                        };
653                                        let right_touching_ptr = tree_node.parent.as_ref().unwrap().1.clone();
654                                        touching_children.push((left_touching_ptr, right_touching_ptr));
655                                    }
656                                }
657                                {
658                                    // the lca
659                                    let node = lca_ptr.read_recursive();
660                                    let tree_node = node.tree_node.as_ref().unwrap();
661                                    let left_touching_ptr = if path_1.is_empty() {
662                                        touching_ptr_1.downgrade()
663                                    } else {
664                                        let left_ptr = path_1[path_1.len() - 1].downgrade();
665                                        let left_idx = tree_node
666                                            .children
667                                            .iter()
668                                            .position(|(ptr, _)| ptr == &left_ptr)
669                                            .expect("should find child");
670                                        tree_node.children[left_idx].1.clone()
671                                    };
672                                    let right_touching_ptr = if path_2.is_empty() {
673                                        touching_ptr_2.downgrade()
674                                    } else {
675                                        let right_ptr = path_2[path_2.len() - 1].downgrade();
676                                        let right_idx = tree_node
677                                            .children
678                                            .iter()
679                                            .position(|(ptr, _)| ptr == &right_ptr)
680                                            .expect("should find child");
681                                        tree_node.children[right_idx].1.clone()
682                                    };
683                                    touching_children.push((left_touching_ptr, right_touching_ptr));
684                                }
685                                if !path_2.is_empty() {
686                                    for (idx, ptr) in path_2.iter().enumerate().rev() {
687                                        let node = ptr.read_recursive();
688                                        let tree_node = node.tree_node.as_ref().unwrap();
689                                        let left_touching_ptr = tree_node.parent.as_ref().unwrap().1.clone();
690                                        let right_touching_ptr = if idx == 0 {
691                                            touching_ptr_2.downgrade()
692                                        } else {
693                                            let last_ptr = path_2[idx - 1].downgrade();
694                                            let idx = tree_node
695                                                .children
696                                                .iter()
697                                                .position(|(ptr, _)| ptr == &last_ptr)
698                                                .expect("should find child");
699                                            tree_node.children[idx].1.clone()
700                                        };
701                                        touching_children.push((left_touching_ptr, right_touching_ptr));
702                                    }
703                                }
704                                touching_children
705                            };
706                            let blossom_node_ptr =
707                                interface_ptr.create_blossom(nodes_circle, touching_children, dual_module);
708                            let primal_node_internal_blossom_ptr = {
709                                // create the corresponding primal node
710                                let belonging = self.downgrade();
711                                let mut module = self.write();
712                                let local_node_index = module.nodes_length;
713                                let node_index = module.nodes_count();
714                                let primal_node_internal_blossom_ptr = if !module.is_fusion
715                                    && local_node_index < module.nodes.len()
716                                    && module.nodes[local_node_index].is_some()
717                                {
718                                    let node_ptr = module.nodes[local_node_index].take().unwrap();
719                                    let mut node = node_ptr.write();
720                                    node.origin = blossom_node_ptr.downgrade();
721                                    node.index = node_index;
722                                    node.tree_node = None;
723                                    node.temporary_match = None;
724                                    node.belonging = belonging;
725                                    drop(node);
726                                    node_ptr
727                                } else {
728                                    PrimalNodeInternalPtr::new_value(PrimalNodeInternal {
729                                        origin: blossom_node_ptr.downgrade(),
730                                        index: node_index,
731                                        tree_node: None,
732                                        temporary_match: None,
733                                        belonging,
734                                    })
735                                };
736                                module.nodes_length += 1;
737                                if module.nodes.len() < module.nodes_length {
738                                    module.nodes.push(None);
739                                }
740                                let cloned_primal_node_internal_blossom_ptr = primal_node_internal_blossom_ptr.clone();
741                                module.nodes[local_node_index] = Some(primal_node_internal_blossom_ptr); // feature `dangerous_pointer`: must push the owner
742                                cloned_primal_node_internal_blossom_ptr
743                            };
744                            // handle other part of the tree structure
745                            let mut children = vec![];
746                            for path in [&path_1, &path_2] {
747                                if !path.is_empty() {
748                                    let mut last_ptr = path[0].downgrade();
749                                    for (height, ptr) in path.iter().enumerate() {
750                                        let mut node = ptr.write();
751                                        if height == 0 {
752                                            let tree_node = node.tree_node.as_ref().unwrap();
753                                            for (child_ptr, child_touching_ptr) in tree_node.children.iter() {
754                                                children.push((child_ptr.clone(), child_touching_ptr.clone()));
755                                            }
756                                        } else {
757                                            if height % 2 == 0 {
758                                                let tree_node = node.tree_node.as_ref().unwrap();
759                                                for (child_ptr, child_touching_ptr) in tree_node.children.iter() {
760                                                    if child_ptr != &last_ptr {
761                                                        // not in the blossom circle
762                                                        children.push((child_ptr.clone(), child_touching_ptr.clone()));
763                                                    }
764                                                }
765                                            }
766                                        }
767                                        node.tree_node = None; // this path is going to be part of the blossom, no longer in the tree
768                                        last_ptr = ptr.downgrade();
769                                    }
770                                }
771                            }
772                            let mut lca = lca_ptr.write();
773                            let lca_tree_node = lca.tree_node.as_ref().unwrap();
774                            {
775                                // add children of lca_ptr
776                                for (child_ptr, child_touching_ptr) in lca_tree_node.children.iter() {
777                                    if !path_1.is_empty() && &path_1[path_1.len() - 1].downgrade() == child_ptr {
778                                        continue;
779                                    }
780                                    if !path_2.is_empty() && &path_2[path_2.len() - 1].downgrade() == child_ptr {
781                                        continue;
782                                    }
783                                    children.push((child_ptr.clone(), child_touching_ptr.clone()));
784                                }
785                            }
786                            if lca_tree_node.parent.is_some() || !children.is_empty() {
787                                let mut primal_node_internal_blossom = primal_node_internal_blossom_ptr.write();
788                                let new_tree_root = if lca_tree_node.depth == 0 {
789                                    primal_node_internal_blossom_ptr.clone()
790                                } else {
791                                    lca_tree_node.root.upgrade_force()
792                                };
793                                let tree_node = AlternatingTreeNode {
794                                    root: new_tree_root.downgrade(),
795                                    parent: lca_tree_node.parent.clone(),
796                                    children,
797                                    depth: lca_tree_node.depth,
798                                    tree_size: if lca_tree_node.depth == 0 { Some(tree_size) } else { None },
799                                };
800                                if lca_tree_node.parent.is_some() {
801                                    let (parent_weak, _) = lca_tree_node.parent.as_ref().unwrap();
802                                    let parent_ptr = parent_weak.upgrade_force();
803                                    lock_write!(parent, parent_ptr);
804                                    let parent_tree_node = parent.tree_node.as_mut().unwrap();
805                                    debug_assert!(
806                                        parent_tree_node.children.len() == 1,
807                                        "lca's parent should be a - node with only one child"
808                                    );
809                                    let touching_ptr = parent_tree_node.children[0].1.clone(); // the touching grandson is not changed when forming blossom
810                                    parent_tree_node.children.clear();
811                                    parent_tree_node
812                                        .children
813                                        .push((primal_node_internal_blossom_ptr.downgrade(), touching_ptr));
814                                }
815                                if !tree_node.children.is_empty() {
816                                    // connect this blossom to the new alternating tree
817                                    for (child_weak, _) in tree_node.children.iter() {
818                                        let child_ptr = child_weak.upgrade_force();
819                                        lock_write!(child, child_ptr);
820                                        let child_tree_node = child.tree_node.as_mut().unwrap();
821                                        debug_assert!(child_tree_node.parent.is_some(), "child should have a parent");
822                                        let touching_ptr = child_tree_node.parent.as_ref().unwrap().1.clone(); // the touching grandson is not changed when forming blossom
823                                        child_tree_node.parent =
824                                            Some((primal_node_internal_blossom_ptr.downgrade(), touching_ptr));
825                                    }
826                                    primal_node_internal_blossom.tree_node = Some(tree_node);
827                                    primal_node_internal_blossom.change_sub_tree_root(lca_tree_node.depth, new_tree_root);
828                                } else {
829                                    primal_node_internal_blossom.tree_node = Some(tree_node);
830                                }
831                            }
832                            lca.tree_node = None;
833                            continue;
834                        } else {
835                            drop(primal_node_internal_1); // unlock
836                            drop(primal_node_internal_2); // unlock
837                            Self::augment_tree_given_matched(
838                                primal_node_internal_ptr_1.clone(),
839                                primal_node_internal_ptr_2.clone(),
840                                touching_ptr_1.downgrade(),
841                                interface_ptr,
842                                dual_module,
843                            );
844                            Self::augment_tree_given_matched(
845                                primal_node_internal_ptr_2.clone(),
846                                primal_node_internal_ptr_1.clone(),
847                                touching_ptr_2.downgrade(),
848                                interface_ptr,
849                                dual_module,
850                            );
851                            continue;
852                        }
853                    }
854                    unreachable!()
855                }
856                MaxUpdateLength::TouchingVirtual((node_ptr, touching_ptr), (virtual_vertex_index, is_mirror)) => {
857                    if self.get_primal_node_internal_ptr_option(&node_ptr).is_none() {
858                        continue;
859                    } // ignore out-of-date event
860                    let primal_node_internal_ptr = self.get_outer_node(self.get_primal_node_internal_ptr(&node_ptr));
861                    let mut primal_node_internal = primal_node_internal_ptr.write();
862                    let grow_state = primal_node_internal.origin.upgrade_force().read_recursive().grow_state;
863                    if grow_state != DualNodeGrowState::Grow {
864                        debug_assert!(
865                            current_conflict_index != 1,
866                            "the first conflict cannot be ignored, otherwise may cause hidden infinite loop"
867                        );
868                        continue; // this is no longer a conflict
869                    }
870                    // this is the most probable case, so put it in the front
871                    if primal_node_internal.is_free() {
872                        primal_node_internal.temporary_match =
873                            Some((MatchTarget::VirtualVertex(virtual_vertex_index), touching_ptr.downgrade()));
874                        if is_mirror {
875                            lock_write!(module, self);
876                            module.possible_break.push(primal_node_internal.index);
877                        }
878                        interface_ptr.set_grow_state(
879                            &primal_node_internal.origin.upgrade_force(),
880                            DualNodeGrowState::Stay,
881                            dual_module,
882                        );
883                        continue;
884                    }
885                    // tree touching virtual boundary will just augment the whole tree
886                    if primal_node_internal.tree_node.is_some() {
887                        if is_mirror {
888                            lock_write!(module, self);
889                            module.possible_break.push(primal_node_internal.index);
890                        }
891                        drop(primal_node_internal);
892                        self.augment_tree_given_virtual_vertex(
893                            primal_node_internal_ptr,
894                            virtual_vertex_index,
895                            touching_ptr.downgrade(),
896                            interface_ptr,
897                            dual_module,
898                        );
899                        continue;
900                    }
901                    unreachable!()
902                }
903                MaxUpdateLength::BlossomNeedExpand(node_ptr) => {
904                    if self.get_primal_node_internal_ptr_option(&node_ptr).is_none() {
905                        continue;
906                    } // ignore out-of-date event
907                      // blossom breaking is assumed to be very rare given our multiple-tree approach, so don't need to optimize for it
908                      // first, isolate this blossom from its alternating tree
909                    let primal_node_internal_ptr = self.get_primal_node_internal_ptr(&node_ptr);
910                    let outer_primal_node_internal_ptr = self.get_outer_node(primal_node_internal_ptr.clone());
911                    if outer_primal_node_internal_ptr != primal_node_internal_ptr {
912                        // this blossom is now wrapped into another blossom, so we don't need to expand it anymore
913                        debug_assert!(
914                            current_conflict_index != 1,
915                            "the first conflict cannot be ignored, otherwise may cause hidden infinite loop"
916                        );
917                        continue;
918                    }
919                    let primal_node_internal = primal_node_internal_ptr.read_recursive();
920                    let grow_state = primal_node_internal.origin.upgrade_force().read_recursive().grow_state;
921                    if grow_state != DualNodeGrowState::Shrink {
922                        debug_assert!(
923                            current_conflict_index != 1,
924                            "the first conflict cannot be ignored, otherwise may cause hidden infinite loop"
925                        );
926                        continue; // this is no longer a conflict
927                    }
928                    // copy the nodes circle
929                    let (nodes_circle, touching_children) = {
930                        let blossom = node_ptr.read_recursive();
931                        match &blossom.class {
932                            DualNodeClass::Blossom {
933                                nodes_circle,
934                                touching_children,
935                            } => (nodes_circle.clone(), touching_children.clone()),
936                            _ => unreachable!("the expanding node is not a blossom"),
937                        }
938                    };
939                    debug_assert!(
940                        primal_node_internal.tree_node.is_some(),
941                        "expanding blossom must belong to an alternating tree"
942                    );
943                    let tree_node = primal_node_internal.tree_node.as_ref().unwrap();
944                    debug_assert!(
945                        tree_node.depth % 2 == 1,
946                        "expanding blossom must a '-' node in an alternating tree"
947                    );
948                    let (parent_ptr, parent_touching_ptr, parent_touching_child_ptr) = {
949                        // remove it from it's parent's tree
950                        let (parent_weak, parent_touching_child_ptr) = &tree_node.parent.as_ref().unwrap();
951                        let parent_ptr = parent_weak.upgrade_force();
952                        lock_write!(parent, parent_ptr);
953                        let parent_tree_node = parent.tree_node.as_mut().unwrap();
954                        let idx = parent_tree_node
955                            .children
956                            .iter()
957                            .position(|ptr| ptr.0 == primal_node_internal_ptr.downgrade())
958                            .expect("should find");
959                        let parent_touching_ptr = parent_tree_node.children[idx].1.clone();
960                        parent_tree_node.children.remove(idx);
961                        parent_tree_node
962                            .children
963                            .retain(|ptr| ptr.0 != primal_node_internal_ptr.downgrade());
964                        (
965                            parent_ptr.clone(),
966                            parent_touching_ptr,
967                            parent_touching_child_ptr
968                                .upgrade_force()
969                                .get_secondary_ancestor_blossom()
970                                .downgrade(),
971                        )
972                    };
973                    let (child_ptr, child_touching_ptr, child_touching_child_ptr) = {
974                        // make children independent trees
975                        debug_assert!(tree_node.children.len() == 1, "a - node must have exactly ONE child");
976                        let child_weak = &tree_node.children[0].0;
977                        let child_touching_child_ptr = tree_node.children[0]
978                            .1
979                            .upgrade_force()
980                            .get_secondary_ancestor_blossom()
981                            .downgrade();
982                        let child_ptr = child_weak.upgrade_force();
983                        let child = child_ptr.read_recursive();
984                        let child_tree_node = child.tree_node.as_ref().unwrap();
985                        // find which blossom-child is touching this child
986                        (
987                            child_ptr.clone(),
988                            child_tree_node.parent.as_ref().unwrap().1.clone(),
989                            child_touching_child_ptr,
990                        )
991                    };
992                    interface_ptr.expand_blossom(node_ptr, dual_module);
993                    // now we need to re-connect all the expanded nodes, by analyzing the relationship of nodes_circle, parent_touching_ptr and child_touching_ptr
994                    let parent_touching_index = nodes_circle
995                        .iter()
996                        .position(|ptr| ptr == &parent_touching_child_ptr)
997                        .expect("touching node should be in the blossom circle");
998                    let child_touching_index = nodes_circle
999                        .iter()
1000                        .position(|ptr| ptr == &child_touching_child_ptr)
1001                        .expect("touching node should be in the blossom circle");
1002                    let mut is_tree_sequence_ascending = true;
1003                    let (match_sequence, tree_sequence) = {
1004                        // tree sequence is from parent to child
1005                        let mut match_sequence = Vec::new();
1006                        let mut tree_sequence = Vec::new();
1007                        match parent_touching_index.cmp(&child_touching_index) {
1008                            Ordering::Equal => {
1009                                tree_sequence.push(parent_touching_index);
1010                                for i in parent_touching_index + 1..nodes_circle.len() {
1011                                    match_sequence.push(i);
1012                                }
1013                                for i in 0..parent_touching_index {
1014                                    match_sequence.push(i);
1015                                }
1016                            }
1017                            Ordering::Greater => {
1018                                if (parent_touching_index - child_touching_index) % 2 == 0 {
1019                                    // [... c <----- p ...]
1020                                    for i in (child_touching_index..parent_touching_index + 1).rev() {
1021                                        tree_sequence.push(i);
1022                                    }
1023                                    is_tree_sequence_ascending = false;
1024                                    for i in parent_touching_index + 1..nodes_circle.len() {
1025                                        match_sequence.push(i);
1026                                    }
1027                                    for i in 0..child_touching_index {
1028                                        match_sequence.push(i);
1029                                    }
1030                                } else {
1031                                    // [--> c ...... p ---]
1032                                    for i in parent_touching_index..nodes_circle.len() {
1033                                        tree_sequence.push(i);
1034                                    }
1035                                    for i in 0..child_touching_index + 1 {
1036                                        tree_sequence.push(i);
1037                                    }
1038                                    for i in child_touching_index + 1..parent_touching_index {
1039                                        match_sequence.push(i);
1040                                    }
1041                                }
1042                            }
1043                            Ordering::Less => {
1044                                if (child_touching_index - parent_touching_index) % 2 == 0 {
1045                                    // [... p -----> c ...]
1046                                    for i in parent_touching_index..child_touching_index + 1 {
1047                                        tree_sequence.push(i);
1048                                    }
1049                                    for i in child_touching_index + 1..nodes_circle.len() {
1050                                        match_sequence.push(i);
1051                                    }
1052                                    for i in 0..parent_touching_index {
1053                                        match_sequence.push(i);
1054                                    }
1055                                } else {
1056                                    // [--- p ...... c <--]
1057                                    for i in (0..parent_touching_index + 1).rev() {
1058                                        tree_sequence.push(i);
1059                                    }
1060                                    for i in (child_touching_index..nodes_circle.len()).rev() {
1061                                        tree_sequence.push(i);
1062                                    }
1063                                    is_tree_sequence_ascending = false;
1064                                    for i in parent_touching_index + 1..child_touching_index {
1065                                        match_sequence.push(i);
1066                                    }
1067                                }
1068                            }
1069                        }
1070                        (match_sequence, tree_sequence)
1071                    };
1072                    debug_assert!(
1073                        match_sequence.len() % 2 == 0 && tree_sequence.len() % 2 == 1,
1074                        "parity of sequence wrong"
1075                    );
1076                    // match the nodes in the match sequence
1077                    for i in (0..match_sequence.len()).step_by(2) {
1078                        let primal_node_internal_ptr_1 =
1079                            self.get_primal_node_internal_ptr(&nodes_circle[match_sequence[i]].upgrade_force());
1080                        let primal_node_internal_ptr_2 =
1081                            self.get_primal_node_internal_ptr(&nodes_circle[match_sequence[i + 1]].upgrade_force());
1082                        debug_assert!(
1083                            (match_sequence[i] + 1) % nodes_circle.len() == match_sequence[i + 1],
1084                            "match sequence should be ascending"
1085                        );
1086                        let touching_ptr_1 = touching_children[match_sequence[i]].1.clone(); // assuming ascending match sequence
1087                        let touching_ptr_2 = touching_children[match_sequence[i + 1]].0.clone(); // assuming ascending match sequence
1088                        let mut primal_node_internal_1 = primal_node_internal_ptr_1.write();
1089                        let mut primal_node_internal_2 = primal_node_internal_ptr_2.write();
1090                        primal_node_internal_1.temporary_match =
1091                            Some((MatchTarget::Peer(primal_node_internal_ptr_2.downgrade()), touching_ptr_1));
1092                        primal_node_internal_2.temporary_match =
1093                            Some((MatchTarget::Peer(primal_node_internal_ptr_1.downgrade()), touching_ptr_2));
1094                        interface_ptr.set_grow_state(
1095                            &primal_node_internal_1.origin.upgrade_force(),
1096                            DualNodeGrowState::Stay,
1097                            dual_module,
1098                        );
1099                        interface_ptr.set_grow_state(
1100                            &primal_node_internal_2.origin.upgrade_force(),
1101                            DualNodeGrowState::Stay,
1102                            dual_module,
1103                        );
1104                    }
1105                    // connect the nodes in the tree sequence to the alternating tree, note that the tree sequence is from parent to child
1106                    for (idx, current_i) in tree_sequence.iter().enumerate() {
1107                        debug_assert!(
1108                            {
1109                                if idx + 1 < tree_sequence.len() {
1110                                    if is_tree_sequence_ascending {
1111                                        (tree_sequence[idx] + 1) % nodes_circle.len() == tree_sequence[idx + 1]
1112                                    } else {
1113                                        (tree_sequence[idx + 1] + 1) % nodes_circle.len() == tree_sequence[idx]
1114                                    }
1115                                } else {
1116                                    true
1117                                }
1118                            },
1119                            "tree sequence orientation must be consistent"
1120                        );
1121                        let current_parent_ptr = if idx == 0 {
1122                            parent_ptr.clone()
1123                        } else {
1124                            self.get_primal_node_internal_ptr(&nodes_circle[tree_sequence[idx - 1]].upgrade_force())
1125                        };
1126                        let current_parent_touching_ptr = if idx == 0 {
1127                            tree_node.parent.as_ref().unwrap().1.clone()
1128                        } else {
1129                            if is_tree_sequence_ascending {
1130                                touching_children[*current_i].0.clone()
1131                            } else {
1132                                touching_children[*current_i].1.clone()
1133                            }
1134                        };
1135                        let current_child_ptr = if idx == tree_sequence.len() - 1 {
1136                            child_ptr.clone()
1137                        } else {
1138                            self.get_primal_node_internal_ptr(&nodes_circle[tree_sequence[idx + 1]].upgrade_force())
1139                        };
1140                        let current_child_touching_ptr = if idx == tree_sequence.len() - 1 {
1141                            tree_node.children[0].1.clone()
1142                        } else {
1143                            if is_tree_sequence_ascending {
1144                                touching_children[*current_i].1.clone()
1145                            } else {
1146                                touching_children[*current_i].0.clone()
1147                            }
1148                        };
1149                        let current_ptr = self.get_primal_node_internal_ptr(&nodes_circle[*current_i].upgrade_force());
1150                        let mut current = current_ptr.write();
1151                        current.tree_node = Some(AlternatingTreeNode {
1152                            root: tree_node.root.clone(),
1153                            parent: Some((current_parent_ptr.downgrade(), current_parent_touching_ptr)),
1154                            children: vec![(current_child_ptr.downgrade(), current_child_touching_ptr)],
1155                            depth: tree_node.depth + idx,
1156                            tree_size: None,
1157                        });
1158                        interface_ptr.set_grow_state(
1159                            &current.origin.upgrade_force(),
1160                            if idx % 2 == 0 {
1161                                DualNodeGrowState::Shrink
1162                            } else {
1163                                DualNodeGrowState::Grow
1164                            },
1165                            dual_module,
1166                        );
1167                    }
1168                    {
1169                        // connect parent
1170                        lock_write!(parent, parent_ptr);
1171                        let parent_tree_node = parent.tree_node.as_mut().unwrap();
1172                        let child_ptr = self.get_primal_node_internal_ptr(&nodes_circle[tree_sequence[0]].upgrade_force());
1173                        parent_tree_node.children.push((child_ptr.downgrade(), parent_touching_ptr));
1174                    }
1175                    {
1176                        // connect child and fix the depth information of the child
1177                        lock_write!(child, child_ptr);
1178                        let child_tree_node = child.tree_node.as_mut().unwrap();
1179                        let parent_ptr = self.get_primal_node_internal_ptr(
1180                            &nodes_circle[tree_sequence[tree_sequence.len() - 1]].upgrade_force(),
1181                        );
1182                        child_tree_node.parent = Some((parent_ptr.downgrade(), child_touching_ptr));
1183                        child.change_sub_tree_root(tree_node.depth + tree_sequence.len(), tree_node.root.upgrade_force());
1184                    }
1185                    {
1186                        // remove it from nodes
1187                        lock_write!(module, self);
1188                        debug_assert_eq!(
1189                            module.get_node(primal_node_internal.index),
1190                            Some(primal_node_internal_ptr.clone()),
1191                            "index wrong"
1192                        );
1193                        module.remove_node(primal_node_internal.index);
1194                    }
1195                }
1196                MaxUpdateLength::VertexShrinkStop(_) => {
1197                    if current_conflict_index == 1 {
1198                        // if this happens, then debug the sorting of conflict events and also check alternating tree: a vertex should never be a floating "-" node
1199                        unreachable!("VertexShrinkStop conflict cannot be solved by primal module, and should be sorted to the last of the heap")
1200                    }
1201                    // just skip and wait for the next round to resolve it, if it's not being resolved already
1202                }
1203                _ => unreachable!("should not resolve these issues"),
1204            }
1205        }
1206    }
1207
1208    fn intermediate_matching<D: DualModuleImpl>(
1209        &mut self,
1210        _interface: &DualModuleInterfacePtr,
1211        _dual_module: &mut D,
1212    ) -> IntermediateMatching {
1213        let mut immediate_matching = IntermediateMatching::new();
1214        let mut flattened_nodes = vec![];
1215        self.flatten_nodes(&mut flattened_nodes);
1216        for primal_node_internal_ptr in flattened_nodes.iter().flatten() {
1217            let primal_node_internal = primal_node_internal_ptr.read_recursive();
1218            debug_assert!(
1219                primal_node_internal.tree_node.is_none(),
1220                "cannot compute perfect matching with active alternating tree"
1221            );
1222            let origin_ptr = primal_node_internal.origin.upgrade_force();
1223            let interface_node = origin_ptr.read_recursive();
1224            if interface_node.parent_blossom.is_some() {
1225                debug_assert_eq!(
1226                    primal_node_internal.temporary_match, None,
1227                    "blossom internal nodes should not be matched"
1228                );
1229                continue; // do not handle this blossom at this level
1230            }
1231            if let Some((match_target, match_touching_ptr)) = primal_node_internal.temporary_match.as_ref() {
1232                match match_target {
1233                    MatchTarget::Peer(peer_internal_weak) => {
1234                        let peer_internal_ptr = peer_internal_weak.upgrade_force();
1235                        let peer_internal = peer_internal_ptr.read_recursive();
1236                        if primal_node_internal.index < peer_internal.index {
1237                            // to avoid duplicate matched pairs
1238                            let peer_touching_ptr = peer_internal.temporary_match.as_ref().unwrap().1.clone();
1239                            immediate_matching.peer_matchings.push((
1240                                (primal_node_internal.origin.upgrade_force(), match_touching_ptr.clone()),
1241                                (peer_internal.origin.upgrade_force(), peer_touching_ptr),
1242                            ));
1243                        }
1244                    }
1245                    MatchTarget::VirtualVertex(virtual_vertex) => {
1246                        immediate_matching.virtual_matchings.push((
1247                            (primal_node_internal.origin.upgrade_force(), match_touching_ptr.clone()),
1248                            *virtual_vertex,
1249                        ));
1250                    }
1251                }
1252            } else {
1253                panic!(
1254                    "cannot compute final matching with unmatched outer node {:?}",
1255                    primal_node_internal_ptr
1256                );
1257            }
1258        }
1259        immediate_matching
1260    }
1261}
1262
1263impl FusionVisualizer for PrimalModuleSerialPtr {
1264    fn snapshot(&self, abbrev: bool) -> serde_json::Value {
1265        // do the sanity check first before taking snapshot
1266        let flattened_nodes = self.sanity_check().unwrap();
1267        let mut primal_nodes = Vec::<serde_json::Value>::new();
1268        for primal_node_ptr in flattened_nodes.iter() {
1269            if let Some(primal_node_ptr) = &primal_node_ptr {
1270                let primal_node = primal_node_ptr.read_recursive();
1271                primal_nodes.push(json!({
1272                    if abbrev { "m" } else { "temporary_match" }: primal_node.temporary_match.as_ref().map(|(match_target, touching_ptr)| {
1273                        match match_target {
1274                            MatchTarget::Peer(peer_weak) => {
1275                                let peer_ptr = peer_weak.upgrade_force();
1276                                json!({
1277                                    if abbrev { "p" } else { "peer" }: peer_ptr.read_recursive().index,
1278                                    if abbrev { "t" } else { "touching" }: touching_ptr.upgrade_force().read_recursive().index,
1279                                })
1280                            },
1281                            MatchTarget::VirtualVertex(vertex_idx) => json!({
1282                                if abbrev { "v" } else { "virtual_vertex" }: vertex_idx,
1283                                if abbrev { "t" } else { "touching" }: touching_ptr.upgrade_force().read_recursive().index,
1284                            }),
1285                        }
1286                    }),
1287                    if abbrev { "t" } else { "tree_node" }: primal_node.tree_node.as_ref().map(|tree_node| {
1288                        json!({
1289                            if abbrev { "r" } else { "root" }: tree_node.root.upgrade_force().read_recursive().index,
1290                            if abbrev { "p" } else { "parent" }: tree_node.parent.as_ref().map(|(weak, _)| weak.upgrade_force().read_recursive().index),
1291                            if abbrev { "pt" } else { "parent_touching" }: tree_node.parent.as_ref().map(|(_, weak)| weak.upgrade_force().read_recursive().index),
1292                            if abbrev { "c" } else { "children" }: tree_node.children.iter().map(|(weak, _)| weak.upgrade_force().read_recursive().index).collect::<Vec<NodeIndex>>(),
1293                            if abbrev { "ct" } else { "children_touching" }: tree_node.children.iter().map(|(_, weak)| weak.upgrade_force().read_recursive().index).collect::<Vec<NodeIndex>>(),
1294                            if abbrev { "d" } else { "depth" }: tree_node.depth,
1295                        })
1296                    }),
1297                }));
1298            } else {
1299                primal_nodes.push(json!(null));
1300            }
1301        }
1302        json!({
1303            "primal_nodes": primal_nodes,
1304        })
1305    }
1306}
1307
1308impl PrimalModuleSerial {
1309    /// return the count of all nodes including those of the children interfaces
1310    pub fn nodes_count(&self) -> NodeNum {
1311        let mut count = self.nodes_length as NodeNum;
1312        if let Some(((_, left_count), (_, right_count))) = &self.children {
1313            count += left_count + right_count;
1314        }
1315        count
1316    }
1317
1318    /// get node ptr by index; if calling from the ancestor module, node_index is absolute, otherwise it's relative
1319    #[allow(clippy::unnecessary_cast)]
1320    pub fn get_node(&self, relative_node_index: NodeIndex) -> Option<PrimalNodeInternalPtr> {
1321        debug_assert!(relative_node_index < self.nodes_count(), "cannot find node in this module");
1322        let mut bias = 0;
1323        if let Some(((left_weak, left_count), (right_weak, right_count))) = &self.children {
1324            if relative_node_index < *left_count {
1325                // this node belongs to the left
1326                return left_weak.upgrade_force().read_recursive().get_node(relative_node_index);
1327            } else if relative_node_index < *left_count + *right_count {
1328                // this node belongs to the right
1329                return right_weak
1330                    .upgrade_force()
1331                    .read_recursive()
1332                    .get_node(relative_node_index - *left_count);
1333            }
1334            bias = left_count + right_count;
1335        }
1336        self.nodes[(relative_node_index - bias) as usize].clone()
1337    }
1338
1339    /// set the corresponding node index to None
1340    #[allow(clippy::unnecessary_cast)]
1341    pub fn remove_node(&mut self, relative_node_index: NodeIndex) {
1342        debug_assert!(relative_node_index < self.nodes_count(), "cannot find node in this module");
1343        let mut bias = 0;
1344        if let Some(((left_weak, left_count), (right_weak, right_count))) = &self.children {
1345            if relative_node_index < *left_count {
1346                // this node belongs to the left
1347                left_weak.upgrade_force().write().remove_node(relative_node_index);
1348                return;
1349            } else if relative_node_index < *left_count + *right_count {
1350                // this node belongs to the right
1351                right_weak
1352                    .upgrade_force()
1353                    .write()
1354                    .remove_node(relative_node_index - *left_count);
1355                return;
1356            }
1357            bias = left_count + right_count;
1358        }
1359        self.nodes[(relative_node_index - bias) as usize] = None;
1360    }
1361}
1362
1363impl PrimalModuleSerialPtr {
1364    pub fn get_primal_node_internal_ptr_option(&self, dual_node_ptr: &DualNodePtr) -> Option<PrimalNodeInternalPtr> {
1365        let module = self.read_recursive();
1366        let dual_node = dual_node_ptr.read_recursive();
1367        let primal_node_internal_ptr = module.get_node(dual_node.index);
1368        if let Some(primal_node_internal_ptr) = &primal_node_internal_ptr {
1369            if module.is_fusion {
1370                primal_node_internal_ptr.update(); // every time it's accessed, make sure it's update-to-date
1371            }
1372            debug_assert!(
1373                dual_node_ptr == &primal_node_internal_ptr.read_recursive().origin.upgrade_force(),
1374                "dual node and primal internal node must corresponds to each other"
1375            );
1376        }
1377        primal_node_internal_ptr
1378    }
1379
1380    pub fn get_primal_node_internal_ptr(&self, dual_node_ptr: &DualNodePtr) -> PrimalNodeInternalPtr {
1381        self.get_primal_node_internal_ptr_option(dual_node_ptr)
1382            .expect("internal primal node must exists")
1383    }
1384
1385    /// get the outer node in the most up-to-date cache
1386    pub fn get_outer_node(&self, primal_node_internal_ptr: PrimalNodeInternalPtr) -> PrimalNodeInternalPtr {
1387        let node = primal_node_internal_ptr.read_recursive();
1388        let origin_ptr = node.origin.upgrade_force();
1389        let interface_node = origin_ptr.read_recursive();
1390        if let Some(parent_dual_node_weak) = &interface_node.parent_blossom {
1391            let parent_dual_node_ptr = parent_dual_node_weak.upgrade_force();
1392            let parent_primal_node_internal_ptr = self.get_primal_node_internal_ptr(&parent_dual_node_ptr);
1393            self.get_outer_node(parent_primal_node_internal_ptr)
1394        } else {
1395            primal_node_internal_ptr.clone()
1396        }
1397    }
1398
1399    /// find the lowest common ancestor (LCA) of two nodes in the alternating tree, return (LCA, path_1, path_2) where path includes leaf but exclude the LCA
1400    pub fn find_lowest_common_ancestor(
1401        &self,
1402        mut primal_node_internal_ptr_1: PrimalNodeInternalPtr,
1403        mut primal_node_internal_ptr_2: PrimalNodeInternalPtr,
1404    ) -> (PrimalNodeInternalPtr, Vec<PrimalNodeInternalPtr>, Vec<PrimalNodeInternalPtr>) {
1405        let (depth_1, depth_2) = {
1406            let primal_node_internal_1 = primal_node_internal_ptr_1.read_recursive();
1407            let primal_node_internal_2 = primal_node_internal_ptr_2.read_recursive();
1408            let tree_node_1 = primal_node_internal_1.tree_node.as_ref().unwrap();
1409            let tree_node_2 = primal_node_internal_2.tree_node.as_ref().unwrap();
1410            debug_assert_eq!(tree_node_1.root, tree_node_2.root, "must belong to the same tree");
1411            (tree_node_1.depth, tree_node_2.depth)
1412        };
1413        let mut path_1 = vec![];
1414        let mut path_2 = vec![];
1415        match depth_1.cmp(&depth_2) {
1416            Ordering::Greater => loop {
1417                let ptr = primal_node_internal_ptr_1.clone();
1418                let primal_node_internal = ptr.read_recursive();
1419                let tree_node = primal_node_internal.tree_node.as_ref().unwrap();
1420                if tree_node.depth == depth_2 {
1421                    break;
1422                }
1423                path_1.push(primal_node_internal_ptr_1.clone());
1424                primal_node_internal_ptr_1 = tree_node.parent.as_ref().unwrap().0.upgrade_force();
1425            },
1426            Ordering::Less => loop {
1427                let ptr = primal_node_internal_ptr_2.clone();
1428                let primal_node_internal = ptr.read_recursive();
1429                let tree_node = primal_node_internal.tree_node.as_ref().unwrap();
1430                if tree_node.depth == depth_1 {
1431                    break;
1432                }
1433                path_2.push(primal_node_internal_ptr_2.clone());
1434                primal_node_internal_ptr_2 = tree_node.parent.as_ref().unwrap().0.upgrade_force();
1435            },
1436            Ordering::Equal => {}
1437        }
1438        // now primal_node_internal_ptr_1 and primal_node_internal_ptr_2 has the same depth, compare them until they're equal
1439        loop {
1440            if primal_node_internal_ptr_1 == primal_node_internal_ptr_2 {
1441                return (primal_node_internal_ptr_1, path_1, path_2);
1442            }
1443            let ptr_1 = primal_node_internal_ptr_1.clone();
1444            let ptr_2 = primal_node_internal_ptr_2.clone();
1445            let primal_node_internal_1 = ptr_1.read_recursive();
1446            let primal_node_internal_2 = ptr_2.read_recursive();
1447            let tree_node_1 = primal_node_internal_1.tree_node.as_ref().unwrap();
1448            let tree_node_2 = primal_node_internal_2.tree_node.as_ref().unwrap();
1449            path_1.push(primal_node_internal_ptr_1.clone());
1450            path_2.push(primal_node_internal_ptr_2.clone());
1451            primal_node_internal_ptr_1 = tree_node_1.parent.as_ref().unwrap().0.upgrade_force();
1452            primal_node_internal_ptr_2 = tree_node_2.parent.as_ref().unwrap().0.upgrade_force();
1453        }
1454    }
1455
1456    /// for any - node, match the children by matching them with + node
1457    pub fn match_subtree<D: DualModuleImpl>(
1458        tree_node_internal_ptr: PrimalNodeInternalPtr,
1459        interface_ptr: &DualModuleInterfacePtr,
1460        dual_module: &mut D,
1461    ) {
1462        let mut tree_node_internal = tree_node_internal_ptr.write();
1463        let tree_node = tree_node_internal.tree_node.as_ref().unwrap();
1464        debug_assert!(tree_node.depth % 2 == 1, "only match - node is possible");
1465        let child_node_internal_ptr = tree_node.children[0].0.upgrade_force();
1466        tree_node_internal.temporary_match = Some((
1467            MatchTarget::Peer(child_node_internal_ptr.downgrade()),
1468            tree_node.children[0].1.clone(),
1469        ));
1470        interface_ptr.set_grow_state(
1471            &tree_node_internal.origin.upgrade_force(),
1472            DualNodeGrowState::Stay,
1473            dual_module,
1474        );
1475        tree_node_internal.tree_node = None;
1476        let mut child_node_internal = child_node_internal_ptr.write();
1477        let child_touching_ptr = child_node_internal
1478            .tree_node
1479            .as_ref()
1480            .unwrap()
1481            .parent
1482            .as_ref()
1483            .unwrap()
1484            .1
1485            .clone();
1486        child_node_internal.temporary_match =
1487            Some((MatchTarget::Peer(tree_node_internal_ptr.downgrade()), child_touching_ptr));
1488        let child_tree_node = child_node_internal.tree_node.as_ref().unwrap();
1489        interface_ptr.set_grow_state(
1490            &child_node_internal.origin.upgrade_force(),
1491            DualNodeGrowState::Stay,
1492            dual_module,
1493        );
1494        for (grandson_ptr, _) in child_tree_node.children.iter() {
1495            Self::match_subtree(grandson_ptr.upgrade_force(), interface_ptr, dual_module);
1496        }
1497        child_node_internal.tree_node = None;
1498    }
1499
1500    /// for any + node, match it with another node will augment the whole tree, breaking out into several matched pairs;
1501    /// `tree_grandson_ptr` is the grandson of tree_node_internal_ptr that touches `match_node_internal_ptr`
1502    pub fn augment_tree_given_matched<D: DualModuleImpl>(
1503        tree_node_internal_ptr: PrimalNodeInternalPtr,
1504        match_node_internal_ptr: PrimalNodeInternalPtr,
1505        tree_touching_ptr: DualNodeWeak,
1506        interface_ptr: &DualModuleInterfacePtr,
1507        dual_module: &mut D,
1508    ) {
1509        let mut tree_node_internal = tree_node_internal_ptr.write();
1510        tree_node_internal.temporary_match =
1511            Some((MatchTarget::Peer(match_node_internal_ptr.downgrade()), tree_touching_ptr));
1512        interface_ptr.set_grow_state(
1513            &tree_node_internal.origin.upgrade_force(),
1514            DualNodeGrowState::Stay,
1515            dual_module,
1516        );
1517        let tree_node = tree_node_internal.tree_node.as_ref().unwrap();
1518        debug_assert!(tree_node.depth % 2 == 0, "only augment + node is possible");
1519        for (child_ptr, _) in tree_node.children.iter() {
1520            if child_ptr != &match_node_internal_ptr.downgrade() {
1521                Self::match_subtree(child_ptr.upgrade_force(), interface_ptr, dual_module);
1522            }
1523        }
1524        if tree_node.depth != 0 {
1525            // it's not root, then we need to match parent to grandparent
1526            let parent_node_internal_weak = tree_node.parent.as_ref().unwrap().0.clone();
1527            let parent_node_internal_ptr = parent_node_internal_weak.upgrade_force();
1528            let grandparent_node_internal_ptr = {
1529                // must unlock parent
1530                let mut parent_node_internal = parent_node_internal_ptr.write();
1531                let parent_tree_node = parent_node_internal.tree_node.as_ref().unwrap();
1532                let grandparent_node_internal_weak = parent_tree_node.parent.as_ref().unwrap().0.clone();
1533                parent_node_internal.temporary_match = Some((
1534                    MatchTarget::Peer(grandparent_node_internal_weak.clone()),
1535                    parent_tree_node.parent.as_ref().unwrap().1.clone(),
1536                ));
1537                parent_node_internal.tree_node = None;
1538                interface_ptr.set_grow_state(
1539                    &parent_node_internal.origin.upgrade_force(),
1540                    DualNodeGrowState::Stay,
1541                    dual_module,
1542                );
1543                grandparent_node_internal_weak.upgrade_force()
1544            };
1545            let grandparent_touching_ptr = {
1546                let grandparent_node_internal = grandparent_node_internal_ptr.read_recursive();
1547                let grandparent_tree_node = grandparent_node_internal.tree_node.as_ref().unwrap();
1548                let idx = grandparent_tree_node
1549                    .children
1550                    .iter()
1551                    .position(|(ptr, _)| ptr == &parent_node_internal_weak)
1552                    .expect("should find child");
1553                grandparent_tree_node.children[idx].1.clone()
1554            };
1555            Self::augment_tree_given_matched(
1556                grandparent_node_internal_ptr,
1557                parent_node_internal_ptr,
1558                grandparent_touching_ptr,
1559                interface_ptr,
1560                dual_module,
1561            );
1562        }
1563        tree_node_internal.tree_node = None;
1564    }
1565
1566    /// for any + node, match it with virtual boundary will augment the whole tree, breaking out into several matched pairs
1567    pub fn augment_tree_given_virtual_vertex<D: DualModuleImpl>(
1568        &self,
1569        tree_node_internal_ptr: PrimalNodeInternalPtr,
1570        virtual_vertex_index: VertexIndex,
1571        tree_touching_ptr: DualNodeWeak,
1572        interface_ptr: &DualModuleInterfacePtr,
1573        dual_module: &mut D,
1574    ) {
1575        let mut tree_node_internal = tree_node_internal_ptr.write();
1576        tree_node_internal.temporary_match = Some((MatchTarget::VirtualVertex(virtual_vertex_index), tree_touching_ptr));
1577        interface_ptr.set_grow_state(
1578            &tree_node_internal.origin.upgrade_force(),
1579            DualNodeGrowState::Stay,
1580            dual_module,
1581        );
1582        let tree_node = tree_node_internal.tree_node.as_ref().unwrap();
1583        debug_assert!(tree_node.depth % 2 == 0, "only augment + node is possible");
1584        for (child_ptr, _) in tree_node.children.iter() {
1585            Self::match_subtree(child_ptr.upgrade_force(), interface_ptr, dual_module);
1586        }
1587        if tree_node.depth != 0 {
1588            // it's not root, then we need to match parent to grandparent
1589            let parent_node_internal_weak = tree_node.parent.as_ref().unwrap().0.clone();
1590            let parent_node_internal_ptr = parent_node_internal_weak.upgrade_force();
1591            let grandparent_node_internal_ptr = {
1592                // must unlock parent
1593                let mut parent_node_internal = parent_node_internal_ptr.write();
1594                let parent_tree_node = parent_node_internal.tree_node.as_ref().unwrap();
1595                let grandparent_node_internal_weak = parent_tree_node.parent.as_ref().unwrap().0.clone();
1596                parent_node_internal.temporary_match = Some((
1597                    MatchTarget::Peer(grandparent_node_internal_weak.clone()),
1598                    parent_tree_node.parent.as_ref().unwrap().1.clone(),
1599                ));
1600                parent_node_internal.tree_node = None;
1601                interface_ptr.set_grow_state(
1602                    &parent_node_internal.origin.upgrade_force(),
1603                    DualNodeGrowState::Stay,
1604                    dual_module,
1605                );
1606                grandparent_node_internal_weak.upgrade_force()
1607            };
1608            let grandparent_touching_ptr = {
1609                let grandparent_node_internal = grandparent_node_internal_ptr.read_recursive();
1610                let grandparent_tree_node = grandparent_node_internal.tree_node.as_ref().unwrap();
1611                let idx = grandparent_tree_node
1612                    .children
1613                    .iter()
1614                    .position(|(ptr, _)| ptr == &parent_node_internal_weak)
1615                    .expect("should find child");
1616                grandparent_tree_node.children[idx].1.clone()
1617            };
1618            Self::augment_tree_given_matched(
1619                grandparent_node_internal_ptr,
1620                parent_node_internal_ptr,
1621                grandparent_touching_ptr,
1622                interface_ptr,
1623                dual_module,
1624            );
1625        }
1626        tree_node_internal.tree_node = None;
1627    }
1628
1629    /// DFS flatten the nodes
1630    #[allow(clippy::unnecessary_cast)]
1631    pub fn flatten_nodes(&self, flattened_nodes: &mut Vec<Option<PrimalNodeInternalPtr>>) {
1632        let module = self.read_recursive();
1633        let flattened_nodes_length = flattened_nodes.len();
1634        // the order matters: left -> right -> myself
1635        if let Some(((left_child_weak, _), (right_child_weak, _))) = &module.children {
1636            left_child_weak.upgrade_force().flatten_nodes(flattened_nodes);
1637            right_child_weak.upgrade_force().flatten_nodes(flattened_nodes);
1638        }
1639        for node_index in 0..module.nodes_length {
1640            let primal_node_internal_ptr = &module.nodes[node_index];
1641            if let Some(primal_node_internal_ptr) = primal_node_internal_ptr {
1642                primal_node_internal_ptr.update();
1643                primal_node_internal_ptr.read_recursive().origin.upgrade_force().update();
1644            }
1645            flattened_nodes.push(primal_node_internal_ptr.clone());
1646        }
1647        debug_assert_eq!(flattened_nodes.len() - flattened_nodes_length, module.nodes_count() as usize);
1648    }
1649
1650    /// fuse two modules by copying the nodes in `other` into myself
1651    #[allow(clippy::unnecessary_cast)]
1652    pub fn slow_fuse(&self, left: &Self, right: &Self) {
1653        let mut module = self.write();
1654        module.is_fusion = true; // for safety
1655        for other in [left, right] {
1656            let mut other_module = other.write();
1657            other_module.is_fusion = true; // enable pointer update
1658            let bias = module.nodes_length as NodeIndex;
1659            for other_node_index in 0..other_module.nodes_length as NodeIndex {
1660                let node_ptr = &other_module.nodes[other_node_index as usize];
1661                if let Some(node_ptr) = node_ptr {
1662                    let mut node = node_ptr.write();
1663                    debug_assert_eq!(node.index, other_node_index);
1664                    node.index += bias;
1665                }
1666                module.nodes_length += 1;
1667                if module.nodes.len() < module.nodes_length {
1668                    module.nodes.push(None);
1669                }
1670                module.nodes[(bias + other_node_index) as usize] = node_ptr.clone();
1671            }
1672            // copy `possible_break`
1673            for node_index in other_module.possible_break.iter() {
1674                module.possible_break.push(*node_index + bias);
1675            }
1676        }
1677    }
1678
1679    /// fuse two modules by (virtually) copying the nodes in `other` into myself, with O(1) time complexity
1680    pub fn fuse(&self, left: &Self, right: &Self) {
1681        let parent_weak = self.downgrade();
1682        let left_weak = left.downgrade();
1683        let right_weak = right.downgrade();
1684        let mut module = self.write();
1685        module.is_fusion = true; // for safety
1686        debug_assert_eq!(module.nodes_length, 0, "fast fuse doesn't support non-empty fuse");
1687        debug_assert!(module.children.is_none(), "cannot fuse twice");
1688        let mut left_module = left.write();
1689        let mut right_module = right.write();
1690        debug_assert!(left_module.parent.is_none(), "cannot fuse an module twice");
1691        debug_assert!(right_module.parent.is_none(), "cannot fuse an module twice");
1692        left_module.parent = Some(parent_weak.clone());
1693        right_module.parent = Some(parent_weak);
1694        left_module.index_bias = 0;
1695        right_module.index_bias = left_module.nodes_count();
1696        module.children = Some((
1697            (left_weak, left_module.nodes_count()),
1698            (right_weak, right_module.nodes_count()),
1699        ));
1700        // the possible_break should be a small subset, thus copying them is fine
1701        for other_module in [left_module, right_module] {
1702            for node_index in other_module.possible_break.iter() {
1703                module.possible_break.push(*node_index + other_module.index_bias);
1704            }
1705        }
1706    }
1707
1708    /// do a sanity check of it's tree structure and internal state
1709    #[allow(clippy::collapsible_else_if)]
1710    pub fn sanity_check(&self) -> Result<Vec<Option<PrimalNodeInternalPtr>>, String> {
1711        let mut flattened_nodes = vec![];
1712        self.flatten_nodes(&mut flattened_nodes);
1713        for (index, primal_module_internal_ptr) in flattened_nodes.iter().enumerate() {
1714            if let Some(primal_module_internal_ptr) = primal_module_internal_ptr {
1715                let primal_module_internal = primal_module_internal_ptr.read_recursive();
1716                if primal_module_internal.index != index as NodeIndex {
1717                    return Err(format!(
1718                        "primal node index wrong: expected {}, actual {}",
1719                        index, primal_module_internal.index
1720                    ));
1721                }
1722                let origin_ptr = primal_module_internal.origin.upgrade_force();
1723                let origin_node = origin_ptr.read_recursive();
1724                if origin_node.index != primal_module_internal.index {
1725                    return Err(format!(
1726                        "origin index wrong: expected {}, actual {}",
1727                        index, origin_node.index
1728                    ));
1729                }
1730                if primal_module_internal.temporary_match.is_some() && primal_module_internal.tree_node.is_some() {
1731                    return Err(format!("{} temporary match and tree node cannot both exists", index));
1732                }
1733                if origin_node.parent_blossom.is_some() {
1734                    if primal_module_internal.tree_node.is_some() {
1735                        return Err(format!("blossom internal node {index} is still in a tree"));
1736                    }
1737                    if primal_module_internal.temporary_match.is_some() {
1738                        return Err(format!("blossom internal node {index} is still matched"));
1739                    }
1740                }
1741                if let Some((match_target, _)) = primal_module_internal.temporary_match.as_ref() {
1742                    if origin_node.grow_state != DualNodeGrowState::Stay {
1743                        return Err(format!("matched node {index} is not set to Stay"));
1744                    }
1745                    match match_target {
1746                        MatchTarget::Peer(peer_weak) => {
1747                            let peer_ptr = peer_weak.upgrade_force();
1748                            let peer = peer_ptr.read_recursive();
1749                            if let Some((peer_match_target, _)) = peer.temporary_match.as_ref() {
1750                                if peer_match_target != &MatchTarget::Peer(primal_module_internal_ptr.downgrade()) {
1751                                    return Err(format!(
1752                                        "match peer {} is not matched with {}, instead it's {:?}",
1753                                        peer.index, index, peer_match_target
1754                                    ));
1755                                }
1756                            } else {
1757                                return Err("match peer is not marked as matched".to_string());
1758                            }
1759                        }
1760                        MatchTarget::VirtualVertex(_vertex_idx) => {} // nothing to check
1761                    }
1762                }
1763                if let Some(tree_node) = primal_module_internal.tree_node.as_ref() {
1764                    // first check if every child's parent is myself
1765                    for (child_weak, _) in tree_node.children.iter() {
1766                        let child_ptr = child_weak.upgrade_force();
1767                        let child = child_ptr.read_recursive();
1768                        if let Some(child_tree_node) = child.tree_node.as_ref() {
1769                            if child_tree_node.parent.as_ref().map(|x| &x.0) != Some(&primal_module_internal_ptr.downgrade())
1770                            {
1771                                return Err(format!(
1772                                    "{}'s child {} has a different parent, link broken",
1773                                    index, child.index
1774                                ));
1775                            }
1776                        } else {
1777                            return Err(format!(
1778                                "{}'s child {} doesn't belong to any tree, link broken",
1779                                index, child.index
1780                            ));
1781                        }
1782                        // check if child is still tracked, i.e. inside self.nodes
1783                        let module = self.read_recursive();
1784                        if child.index >= module.nodes_count() || module.get_node(child.index).is_none() {
1785                            return Err(format!("child's index {} is not in the interface", child.index));
1786                        }
1787                        let tracked_child_ptr = module.get_node(child.index).unwrap();
1788                        if tracked_child_ptr != child_ptr {
1789                            return Err(format!(
1790                                "the tracked ptr of child {} is not what's being pointed",
1791                                child.index
1792                            ));
1793                        }
1794                    }
1795                    // then check if I'm my parent's child
1796                    if let Some((parent_weak, _)) = tree_node.parent.as_ref() {
1797                        let parent_ptr = parent_weak.upgrade_force();
1798                        let parent = parent_ptr.read_recursive();
1799                        if let Some(parent_tree_node) = parent.tree_node.as_ref() {
1800                            let mut found_match_count = 0;
1801                            for (node_ptr, _) in parent_tree_node.children.iter() {
1802                                if node_ptr == &primal_module_internal_ptr.downgrade() {
1803                                    found_match_count += 1;
1804                                }
1805                            }
1806                            if found_match_count != 1 {
1807                                return Err(format!(
1808                                    "{} is the parent of {} but the child only presents {} times",
1809                                    parent.index, index, found_match_count
1810                                ));
1811                            }
1812                        } else {
1813                            return Err(format!(
1814                                "{}'s parent {} doesn't belong to any tree, link broken",
1815                                index, parent.index
1816                            ));
1817                        }
1818                        // check if parent is still tracked, i.e. inside self.nodes
1819                        let module = self.read_recursive();
1820                        if parent.index >= module.nodes_count() || module.get_node(parent.index).is_none() {
1821                            return Err(format!("parent's index {} is not in the interface", parent.index));
1822                        }
1823                        let tracked_parent_ptr = module.get_node(parent.index).unwrap();
1824                        if tracked_parent_ptr != parent_ptr {
1825                            return Err(format!(
1826                                "the tracked ptr of child {} is not what's being pointed",
1827                                parent.index
1828                            ));
1829                        }
1830                    } else {
1831                        if tree_node.root != primal_module_internal_ptr.downgrade() {
1832                            return Err(format!("{} is not the root of the tree, yet it has no parent", index));
1833                        }
1834                    }
1835                    // then check if the root and the depth is correct
1836                    let mut current_ptr = primal_module_internal_ptr.clone();
1837                    let mut current_up = 0;
1838                    loop {
1839                        let current = current_ptr.read_recursive();
1840                        // check if current is still tracked, i.e. inside self.nodes
1841                        let module = self.read_recursive();
1842                        if current.index >= module.nodes_count() || module.get_node(current.index).is_none() {
1843                            return Err(format!("current's index {} is not in the interface", current.index));
1844                        }
1845                        let tracked_current_ptr = module.get_node(current.index).unwrap();
1846                        if tracked_current_ptr != current_ptr {
1847                            return Err(format!(
1848                                "the tracked ptr of current {} is not what's being pointed",
1849                                current.index
1850                            ));
1851                        }
1852                        // go to parent
1853                        if let Some(current_tree_node) = current.tree_node.as_ref() {
1854                            if let Some((current_parent_ptr, _)) = current_tree_node.parent.as_ref() {
1855                                let current_parent_ptr = current_parent_ptr.clone();
1856                                drop(current);
1857                                current_ptr = current_parent_ptr.upgrade_force();
1858                                current_up += 1;
1859                            } else {
1860                                // confirm this is root and then break the loop
1861                                if current_tree_node.root != current_ptr.downgrade() {
1862                                    return Err(format!(
1863                                        "current {} is not the root of the tree, yet it has no parent",
1864                                        current.index
1865                                    ));
1866                                }
1867                                break;
1868                            }
1869                        } else {
1870                            return Err(format!(
1871                                "climbing up from {} to {} but it doesn't belong to a tree anymore",
1872                                index, current.index
1873                            ));
1874                        }
1875                    }
1876                    if current_up != tree_node.depth {
1877                        return Err(format!(
1878                            "{} is marked with depth {} but the real depth is {}",
1879                            index, tree_node.depth, current_up
1880                        ));
1881                    }
1882                    if current_ptr.downgrade() != tree_node.root {
1883                        return Err(format!(
1884                            "{} is marked with root {:?} but the real root is {:?}",
1885                            index, tree_node.root, current_ptr
1886                        ));
1887                    }
1888                }
1889            }
1890        }
1891        Ok(flattened_nodes)
1892    }
1893
1894    /// collapse a tree into a single blossom, just like what union-find decoder does. No MWPM guarantee once this is called.
1895    pub fn collapse_tree<D: DualModuleImpl>(
1896        &self,
1897        primal_node_internal_ptr: PrimalNodeInternalPtr,
1898        interface_ptr: &DualModuleInterfacePtr,
1899        dual_module: &mut D,
1900    ) {
1901        let mut children = vec![];
1902        primal_node_internal_ptr.flatten_tree(&mut children);
1903        let nodes_circle: Vec<_> = children
1904            .iter()
1905            .map(|ptr| ptr.read_recursive().origin.clone().upgrade_force())
1906            .collect();
1907        // since we no longer care the internal structure of the tree, we can just construct arbitrary touching list
1908        let touching_children: Vec<_> = children
1909            .iter()
1910            .map(|ptr| {
1911                let node = ptr.read_recursive();
1912                let tree_node = node.tree_node.as_ref().unwrap();
1913                let touching = if let Some((_, touching)) = tree_node.parent.as_ref() {
1914                    touching.clone()
1915                } else {
1916                    tree_node.children[0].1.clone()
1917                };
1918                (touching.clone(), touching) // which touching doesn't matter; union-find decoder doesn't care the internal
1919            })
1920            .collect();
1921        let blossom_node_ptr = interface_ptr.create_blossom(nodes_circle, touching_children, dual_module);
1922        // create the blossom primal node
1923        {
1924            // create the corresponding primal node
1925            let belonging = self.downgrade();
1926            let mut module = self.write();
1927            let local_node_index = module.nodes_length;
1928            let node_index = module.nodes_count();
1929            let primal_node_internal_blossom_ptr =
1930                if !module.is_fusion && local_node_index < module.nodes.len() && module.nodes[local_node_index].is_some() {
1931                    let node_ptr = module.nodes[local_node_index].take().unwrap();
1932                    let mut node = node_ptr.write();
1933                    node.origin = blossom_node_ptr.downgrade();
1934                    node.index = node_index;
1935                    node.tree_node = None;
1936                    node.temporary_match = None;
1937                    node.belonging = belonging;
1938                    drop(node);
1939                    node_ptr
1940                } else {
1941                    PrimalNodeInternalPtr::new_value(PrimalNodeInternal {
1942                        origin: blossom_node_ptr.downgrade(),
1943                        index: node_index,
1944                        tree_node: None,
1945                        temporary_match: None,
1946                        belonging,
1947                    })
1948                };
1949            module.nodes_length += 1;
1950            if module.nodes.len() < module.nodes_length {
1951                module.nodes.push(None);
1952            }
1953            module.nodes[local_node_index] = Some(primal_node_internal_blossom_ptr.clone());
1954        };
1955        // remove the tree structure
1956        for ptr in children.iter() {
1957            let mut node = ptr.write();
1958            node.tree_node = None;
1959        }
1960    }
1961}
1962
1963impl PrimalNodeInternalPtr {
1964    /// DFS flatten the children of a tree
1965    pub fn flatten_tree(&self, flattened_nodes: &mut Vec<PrimalNodeInternalPtr>) {
1966        flattened_nodes.push(self.clone());
1967        let node = self.read_recursive();
1968        let tree_node = node.tree_node.as_ref().unwrap();
1969        for (child_weak, _) in tree_node.children.iter() {
1970            let child_ptr = child_weak.upgrade_force();
1971            child_ptr.flatten_tree(flattened_nodes);
1972        }
1973    }
1974}
1975
1976#[cfg(test)]
1977pub mod tests {
1978    use super::super::dual_module_serial::*;
1979    use super::super::example_codes::*;
1980    #[cfg(feature = "blossom_v")]
1981    use super::super::*;
1982    use super::*;
1983
1984    pub fn primal_module_serial_basic_standard_syndrome_optional_viz(
1985        d: VertexNum,
1986        visualize_filename: Option<String>,
1987        defect_vertices: Vec<VertexIndex>,
1988        final_dual: Weight,
1989    ) -> (DualModuleInterfacePtr, PrimalModuleSerialPtr, DualModuleSerial) {
1990        primal_module_serial_basic_standard_syndrome_optional_viz_max_tree_size(
1991            d,
1992            visualize_filename,
1993            defect_vertices,
1994            final_dual,
1995            usize::MAX,
1996        )
1997    }
1998
1999    pub fn primal_module_serial_basic_standard_syndrome_optional_viz_max_tree_size(
2000        d: VertexNum,
2001        visualize_filename: Option<String>,
2002        defect_vertices: Vec<VertexIndex>,
2003        final_dual: Weight,
2004        max_tree_size: usize,
2005    ) -> (DualModuleInterfacePtr, PrimalModuleSerialPtr, DualModuleSerial) {
2006        println!("{defect_vertices:?}");
2007        let half_weight = 500;
2008        let mut code = CodeCapacityPlanarCode::new(d, 0.1, half_weight);
2009        let mut visualizer = match visualize_filename.as_ref() {
2010            Some(visualize_filename) => {
2011                let visualizer = Visualizer::new(
2012                    Some(visualize_data_folder() + visualize_filename.as_str()),
2013                    code.get_positions(),
2014                    true,
2015                )
2016                .unwrap();
2017                print_visualize_link(visualize_filename.clone());
2018                Some(visualizer)
2019            }
2020            None => None,
2021        };
2022        // create dual module
2023        let initializer = code.get_initializer();
2024        let mut dual_module = DualModuleSerial::new_empty(&initializer);
2025        // create primal module
2026        let mut primal_module = PrimalModuleSerialPtr::new_empty(&initializer);
2027        primal_module.write().debug_resolve_only_one = true; // to enable debug mode
2028                                                             // try to work on a simple syndrome
2029        primal_module.write().max_tree_size = max_tree_size;
2030        code.set_defect_vertices(&defect_vertices);
2031        let interface_ptr = DualModuleInterfacePtr::new_empty();
2032        primal_module.solve_visualizer(&interface_ptr, &code.get_syndrome(), &mut dual_module, visualizer.as_mut());
2033        let perfect_matching = primal_module.perfect_matching(&interface_ptr, &mut dual_module);
2034        let mut subgraph_builder = SubGraphBuilder::new(&initializer);
2035        subgraph_builder.load_perfect_matching(&perfect_matching);
2036        let subgraph = subgraph_builder.get_subgraph();
2037        if let Some(visualizer) = visualizer.as_mut() {
2038            visualizer
2039                .snapshot_combined(
2040                    "perfect matching and subgraph".to_string(),
2041                    vec![
2042                        &interface_ptr,
2043                        &dual_module,
2044                        &perfect_matching,
2045                        &VisualizeSubgraph::new(&subgraph),
2046                    ],
2047                )
2048                .unwrap();
2049        }
2050        assert_eq!(
2051            interface_ptr.sum_dual_variables(),
2052            subgraph_builder.total_weight(),
2053            "unmatched sum dual variables"
2054        );
2055        assert_eq!(
2056            interface_ptr.sum_dual_variables(),
2057            final_dual * 2 * half_weight,
2058            "unexpected final dual variable sum"
2059        );
2060        (interface_ptr, primal_module, dual_module)
2061    }
2062
2063    pub fn primal_module_serial_basic_standard_syndrome(
2064        d: VertexNum,
2065        visualize_filename: String,
2066        defect_vertices: Vec<VertexIndex>,
2067        final_dual: Weight,
2068    ) -> (DualModuleInterfacePtr, PrimalModuleSerialPtr, DualModuleSerial) {
2069        primal_module_serial_basic_standard_syndrome_optional_viz(d, Some(visualize_filename), defect_vertices, final_dual)
2070    }
2071
2072    /// test a simple blossom
2073    #[test]
2074    fn primal_module_serial_basic_1() {
2075        // cargo test primal_module_serial_basic_1 -- --nocapture
2076        let visualize_filename = "primal_module_serial_basic_1.json".to_string();
2077        let defect_vertices = vec![18, 26, 34];
2078        primal_module_serial_basic_standard_syndrome(7, visualize_filename, defect_vertices, 4);
2079    }
2080
2081    /// test a free node conflict with a virtual boundary
2082    #[test]
2083    fn primal_module_serial_basic_2() {
2084        // cargo test primal_module_serial_basic_2 -- --nocapture
2085        let visualize_filename = "primal_module_serial_basic_2.json".to_string();
2086        let defect_vertices = vec![16];
2087        primal_module_serial_basic_standard_syndrome(7, visualize_filename, defect_vertices, 1);
2088    }
2089
2090    /// test a free node conflict with a matched node (with virtual boundary)
2091    #[test]
2092    fn primal_module_serial_basic_3() {
2093        // cargo test primal_module_serial_basic_3 -- --nocapture
2094        let visualize_filename = "primal_module_serial_basic_3.json".to_string();
2095        let defect_vertices = vec![16, 26];
2096        primal_module_serial_basic_standard_syndrome(7, visualize_filename, defect_vertices, 3);
2097    }
2098
2099    /// test blossom shrinking and expanding
2100    #[test]
2101    fn primal_module_serial_basic_4() {
2102        // cargo test primal_module_serial_basic_4 -- --nocapture
2103        let visualize_filename = "primal_module_serial_basic_4.json".to_string();
2104        let defect_vertices = vec![16, 52, 65, 76, 112];
2105        primal_module_serial_basic_standard_syndrome(11, visualize_filename, defect_vertices, 10);
2106    }
2107
2108    /// test blossom conflicts with vertex
2109    #[test]
2110    fn primal_module_serial_basic_5() {
2111        // cargo test primal_module_serial_basic_5 -- --nocapture
2112        let visualize_filename = "primal_module_serial_basic_5.json".to_string();
2113        let defect_vertices = vec![39, 51, 61, 62, 63, 64, 65, 75, 87, 67];
2114        primal_module_serial_basic_standard_syndrome(11, visualize_filename, defect_vertices, 6);
2115    }
2116
2117    /// test cascaded blossom
2118    #[test]
2119    fn primal_module_serial_basic_6() {
2120        // cargo test primal_module_serial_basic_6 -- --nocapture
2121        let visualize_filename = "primal_module_serial_basic_6.json".to_string();
2122        let defect_vertices = vec![39, 51, 61, 62, 63, 64, 65, 75, 87];
2123        primal_module_serial_basic_standard_syndrome(11, visualize_filename, defect_vertices, 6);
2124    }
2125
2126    /// test two alternating trees conflict with each other
2127    #[test]
2128    fn primal_module_serial_basic_7() {
2129        // cargo test primal_module_serial_basic_7 -- --nocapture
2130        let visualize_filename = "primal_module_serial_basic_7.json".to_string();
2131        let defect_vertices = vec![37, 61, 63, 66, 68, 44];
2132        primal_module_serial_basic_standard_syndrome(11, visualize_filename, defect_vertices, 7);
2133    }
2134
2135    /// test an alternating tree touches a virtual boundary
2136    #[test]
2137    fn primal_module_serial_basic_8() {
2138        // cargo test primal_module_serial_basic_8 -- --nocapture
2139        let visualize_filename = "primal_module_serial_basic_8.json".to_string();
2140        let defect_vertices = vec![61, 64, 67];
2141        primal_module_serial_basic_standard_syndrome(11, visualize_filename, defect_vertices, 5);
2142    }
2143
2144    /// test a matched node (with virtual boundary) conflicts with an alternating tree
2145    #[test]
2146    fn primal_module_serial_basic_9() {
2147        // cargo test primal_module_serial_basic_9 -- --nocapture
2148        let visualize_filename = "primal_module_serial_basic_9.json".to_string();
2149        let defect_vertices = vec![60, 63, 66, 30];
2150        primal_module_serial_basic_standard_syndrome(11, visualize_filename, defect_vertices, 6);
2151    }
2152
2153    /// test the error pattern in the paper
2154    #[test]
2155    fn primal_module_serial_basic_10() {
2156        // cargo test primal_module_serial_basic_10 -- --nocapture
2157        let visualize_filename = "primal_module_serial_basic_10.json".to_string();
2158        let defect_vertices = vec![39, 52, 63, 90, 100];
2159        primal_module_serial_basic_standard_syndrome(11, visualize_filename, defect_vertices, 9);
2160    }
2161
2162    /// test the union-find decoder
2163    #[test]
2164    fn primal_module_union_find_basic_10() {
2165        // cargo test primal_module_union_find_basic_10 -- --nocapture
2166        let visualize_filename = "primal_module_union_find_basic_10.json".to_string();
2167        let defect_vertices = vec![39, 52, 63, 90, 100];
2168        let func = primal_module_serial_basic_standard_syndrome_optional_viz_max_tree_size;
2169        func(11, Some(visualize_filename), defect_vertices, 9, 0);
2170        // func(11, Some(visualize_filename), defect_vertices, 9, 3);
2171    }
2172
2173    /// test the error pattern in the paper
2174    #[test]
2175    fn primal_module_serial_default_example() {
2176        // cargo test primal_module_serial_default_example -- --nocapture
2177        let visualize_filename = static_visualize_data_filename();
2178        let defect_vertices = vec![39, 52, 63, 90, 100];
2179        primal_module_serial_basic_standard_syndrome(11, visualize_filename, defect_vertices, 9);
2180    }
2181
2182    /// debug a case of deadlock after changing the strategy of detecting conflicts around VertexShrinkStop;
2183    /// reason: forget to check whether conflicting nodes are growing: only growing one should be reported
2184    #[test]
2185    fn primal_module_serial_basic_11() {
2186        // cargo test primal_module_serial_basic_11 -- --nocapture
2187        let visualize_filename = "primal_module_serial_basic_11.json".to_string();
2188        let defect_vertices = vec![
2189            13, 29, 52, 53, 58, 60, 71, 74, 76, 87, 96, 107, 112, 118, 121, 122, 134, 137, 141, 145, 152, 153, 154, 156,
2190            157, 169, 186, 202, 203, 204, 230, 231,
2191        ];
2192        primal_module_serial_basic_standard_syndrome(15, visualize_filename, defect_vertices, 20);
2193    }
2194
2195    /// debug a case where it disagree with blossom V library, mine reports 11866, blossom V reports 12284
2196    #[test]
2197    #[cfg(feature = "blossom_v")]
2198    fn primal_module_debug_1() {
2199        // cargo test primal_module_debug_1 -- --nocapture
2200        let visualize_filename = "primal_module_debug_1.json".to_string();
2201        let defect_vertices = vec![
2202            34, 35, 84, 89, 92, 100, 141, 145, 149, 164, 193, 201, 205, 220, 235, 242, 243, 260, 261, 290, 300, 308, 309,
2203            315, 317,
2204        ];
2205        let max_half_weight = 500;
2206        let mut code = CircuitLevelPlanarCode::new(7, 7, 0.01, max_half_weight);
2207        let mut visualizer = Visualizer::new(
2208            Some(visualize_data_folder() + visualize_filename.as_str()),
2209            code.get_positions(),
2210            true,
2211        )
2212        .unwrap();
2213        print_visualize_link(visualize_filename.clone());
2214        let initializer = code.get_initializer();
2215        // blossom V ground truth
2216        let blossom_mwpm_result = blossom_v_mwpm(&initializer, &defect_vertices);
2217        println!("blossom_mwpm_result: {blossom_mwpm_result:?}");
2218        let blossom_details = detailed_matching(&initializer, &defect_vertices, &blossom_mwpm_result);
2219        let mut blossom_total_weight = 0;
2220        for detail in blossom_details.iter() {
2221            println!("    {detail:?}");
2222            blossom_total_weight += detail.weight;
2223        }
2224        // create dual module
2225        let mut dual_module = DualModuleSerial::new_empty(&initializer);
2226        // create primal module
2227        let mut primal_module = PrimalModuleSerialPtr::new_empty(&initializer);
2228        primal_module.write().debug_resolve_only_one = true; // to enable debug mode
2229                                                             // try to work on a simple syndrome
2230        code.set_defect_vertices(&defect_vertices);
2231        let interface_ptr = DualModuleInterfacePtr::new_empty();
2232        primal_module.solve_visualizer(&interface_ptr, &code.get_syndrome(), &mut dual_module, Some(&mut visualizer));
2233        let fusion_mwpm = primal_module.perfect_matching(&interface_ptr, &mut dual_module);
2234        let fusion_mwpm_result = fusion_mwpm.legacy_get_mwpm_result(defect_vertices.clone());
2235        let fusion_details = detailed_matching(&initializer, &defect_vertices, &fusion_mwpm_result);
2236        let mut fusion_total_weight = 0;
2237        for detail in fusion_details.iter() {
2238            println!("    {detail:?}");
2239            fusion_total_weight += detail.weight;
2240        }
2241        assert_eq!(
2242            fusion_total_weight, blossom_total_weight,
2243            "unexpected final dual variable sum"
2244        );
2245        {
2246            // also test subgraph builder
2247            let mut subgraph_builder = SubGraphBuilder::new(&initializer);
2248            subgraph_builder.load_perfect_matching(&fusion_mwpm);
2249            assert_eq!(
2250                subgraph_builder.total_weight(),
2251                blossom_total_weight,
2252                "unexpected final dual variable sum"
2253            );
2254        }
2255        assert_eq!(
2256            interface_ptr.sum_dual_variables(),
2257            blossom_total_weight,
2258            "unexpected final dual variable sum"
2259        );
2260    }
2261
2262    /// debug a case where it disagree with blossom V library, mine reports 33000, blossom V reports 34000
2263    #[test]
2264    #[cfg(feature = "blossom_v")]
2265    fn primal_module_debug_2() {
2266        // cargo test primal_module_debug_2 -- --nocapture
2267        let visualize_filename = "primal_module_debug_2.json".to_string();
2268        let defect_vertices = vec![
2269            7, 8, 10, 22, 23, 24, 25, 37, 38, 39, 40, 42, 43, 69, 57, 59, 60, 72, 76, 93, 109, 121, 123, 125, 135, 136, 137,
2270            138, 139, 140, 141, 150, 151, 153, 154, 155, 166, 171, 172, 181, 183, 184, 188, 200, 204, 219, 233,
2271        ];
2272        let max_half_weight = 500;
2273        let mut code = CodeCapacityPlanarCode::new(15, 0.3, max_half_weight);
2274        let mut visualizer = Visualizer::new(
2275            Some(visualize_data_folder() + visualize_filename.as_str()),
2276            code.get_positions(),
2277            true,
2278        )
2279        .unwrap();
2280        print_visualize_link(visualize_filename.clone());
2281        let initializer = code.get_initializer();
2282        // blossom V ground truth
2283        let blossom_mwpm_result = blossom_v_mwpm(&initializer, &defect_vertices);
2284        let blossom_details = detailed_matching(&initializer, &defect_vertices, &blossom_mwpm_result);
2285        let mut blossom_total_weight = 0;
2286        for detail in blossom_details.iter() {
2287            println!("    {detail:?}");
2288            blossom_total_weight += detail.weight;
2289        }
2290        // create dual module
2291        let mut dual_module = DualModuleSerial::new_empty(&initializer);
2292        // create primal module
2293        let mut primal_module = PrimalModuleSerialPtr::new_empty(&initializer);
2294        primal_module.write().debug_resolve_only_one = true; // to enable debug mode
2295                                                             // try to work on a simple syndrome
2296        code.set_defect_vertices(&defect_vertices);
2297        let interface_ptr = DualModuleInterfacePtr::new_empty();
2298        primal_module.solve_visualizer(&interface_ptr, &code.get_syndrome(), &mut dual_module, Some(&mut visualizer));
2299        let fusion_mwpm = primal_module.perfect_matching(&interface_ptr, &mut dual_module);
2300        let fusion_mwpm_result = fusion_mwpm.legacy_get_mwpm_result(defect_vertices.clone());
2301        let fusion_details = detailed_matching(&initializer, &defect_vertices, &fusion_mwpm_result);
2302        let mut fusion_total_weight = 0;
2303        for detail in fusion_details.iter() {
2304            println!("    {detail:?}");
2305            fusion_total_weight += detail.weight;
2306        }
2307        assert_eq!(
2308            fusion_total_weight, blossom_total_weight,
2309            "unexpected final dual variable sum"
2310        );
2311        {
2312            // also test subgraph builder
2313            let mut subgraph_builder = SubGraphBuilder::new(&initializer);
2314            subgraph_builder.load_perfect_matching(&fusion_mwpm);
2315            assert_eq!(
2316                subgraph_builder.total_weight(),
2317                blossom_total_weight,
2318                "unexpected final dual variable sum"
2319            );
2320        }
2321        assert_eq!(
2322            interface_ptr.sum_dual_variables(),
2323            blossom_total_weight,
2324            "unexpected final dual variable sum"
2325        );
2326    }
2327
2328    /// debug a case where it disagree with blossom V library, mine reports 16000, blossom V reports 17000
2329    #[test]
2330    #[cfg(feature = "blossom_v")]
2331    fn primal_module_debug_3() {
2332        // cargo test primal_module_debug_3 -- --nocapture
2333        let visualize_filename = "primal_module_debug_3.json".to_string();
2334        let defect_vertices = vec![
2335            17, 34, 36, 54, 55, 74, 95, 96, 112, 113, 114, 115, 116, 130, 131, 132, 134, 150, 151, 154, 156, 171, 172, 173,
2336            190,
2337        ];
2338        let max_half_weight = 500;
2339        let mut code = CodeCapacityPlanarCode::new(19, 0.499, max_half_weight);
2340        let mut visualizer = Visualizer::new(
2341            Some(visualize_data_folder() + visualize_filename.as_str()),
2342            code.get_positions(),
2343            true,
2344        )
2345        .unwrap();
2346        print_visualize_link(visualize_filename.clone());
2347        let initializer = code.get_initializer();
2348        // blossom V ground truth
2349        let blossom_mwpm_result = blossom_v_mwpm(&initializer, &defect_vertices);
2350        let blossom_details = detailed_matching(&initializer, &defect_vertices, &blossom_mwpm_result);
2351        let mut blossom_total_weight = 0;
2352        for detail in blossom_details.iter() {
2353            println!("    {detail:?}");
2354            blossom_total_weight += detail.weight;
2355        }
2356        // create dual module
2357        let mut dual_module = DualModuleSerial::new_empty(&initializer);
2358        // create primal module
2359        let mut primal_module = PrimalModuleSerialPtr::new_empty(&initializer);
2360        primal_module.write().debug_resolve_only_one = true; // to enable debug mode
2361                                                             // try to work on a simple syndrome
2362        code.set_defect_vertices(&defect_vertices);
2363        let interface_ptr = DualModuleInterfacePtr::new_empty();
2364        primal_module.solve_visualizer(&interface_ptr, &code.get_syndrome(), &mut dual_module, Some(&mut visualizer));
2365        let fusion_mwpm = primal_module.perfect_matching(&interface_ptr, &mut dual_module);
2366        let fusion_mwpm_result = fusion_mwpm.legacy_get_mwpm_result(defect_vertices.clone());
2367        let fusion_details = detailed_matching(&initializer, &defect_vertices, &fusion_mwpm_result);
2368        let mut fusion_total_weight = 0;
2369        for detail in fusion_details.iter() {
2370            println!("    {detail:?}");
2371            fusion_total_weight += detail.weight;
2372        }
2373        assert_eq!(
2374            fusion_total_weight, blossom_total_weight,
2375            "unexpected final dual variable sum"
2376        );
2377        {
2378            // also test subgraph builder
2379            let mut subgraph_builder = SubGraphBuilder::new(&initializer);
2380            subgraph_builder.load_perfect_matching(&fusion_mwpm);
2381            assert_eq!(
2382                subgraph_builder.total_weight(),
2383                blossom_total_weight,
2384                "unexpected final dual variable sum"
2385            );
2386        }
2387        assert_eq!(
2388            interface_ptr.sum_dual_variables(),
2389            blossom_total_weight,
2390            "unexpected final dual variable sum"
2391        );
2392    }
2393
2394    /// debug a case where it disagree with blossom V library, mine reports 9000, blossom V reports 7000
2395    #[test]
2396    #[cfg(feature = "blossom_v")]
2397    fn primal_module_debug_4() {
2398        // cargo test primal_module_debug_4 -- --nocapture
2399        let visualize_filename = "primal_module_debug_4.json".to_string();
2400        let defect_vertices = vec![1, 3, 6, 8, 9, 11, 13];
2401        let max_half_weight = 500;
2402        let mut code = CodeCapacityRepetitionCode::new(15, 0.499, max_half_weight);
2403        let mut visualizer = Visualizer::new(
2404            Some(visualize_data_folder() + visualize_filename.as_str()),
2405            code.get_positions(),
2406            true,
2407        )
2408        .unwrap();
2409        print_visualize_link(visualize_filename.clone());
2410        let initializer = code.get_initializer();
2411        // blossom V ground truth
2412        let blossom_mwpm_result = blossom_v_mwpm(&initializer, &defect_vertices);
2413        let blossom_details = detailed_matching(&initializer, &defect_vertices, &blossom_mwpm_result);
2414        let mut blossom_total_weight = 0;
2415        for detail in blossom_details.iter() {
2416            println!("    {detail:?}");
2417            blossom_total_weight += detail.weight;
2418        }
2419        // create dual module
2420        let mut dual_module = DualModuleSerial::new_empty(&initializer);
2421        // create primal module
2422        let mut primal_module = PrimalModuleSerialPtr::new_empty(&initializer);
2423        primal_module.write().debug_resolve_only_one = true; // to enable debug mode
2424                                                             // try to work on a simple syndrome
2425        code.set_defect_vertices(&defect_vertices);
2426        let interface_ptr = DualModuleInterfacePtr::new_empty();
2427        primal_module.solve_visualizer(&interface_ptr, &code.get_syndrome(), &mut dual_module, Some(&mut visualizer));
2428        let fusion_mwpm = primal_module.perfect_matching(&interface_ptr, &mut dual_module);
2429        let fusion_mwpm_result = fusion_mwpm.legacy_get_mwpm_result(defect_vertices.clone());
2430        let fusion_details = detailed_matching(&initializer, &defect_vertices, &fusion_mwpm_result);
2431        let mut fusion_total_weight = 0;
2432        for detail in fusion_details.iter() {
2433            println!("    {detail:?}");
2434            fusion_total_weight += detail.weight;
2435        }
2436        assert_eq!(
2437            fusion_total_weight, blossom_total_weight,
2438            "unexpected final dual variable sum"
2439        );
2440        {
2441            // also test subgraph builder
2442            let mut subgraph_builder = SubGraphBuilder::new(&initializer);
2443            subgraph_builder.load_perfect_matching(&fusion_mwpm);
2444            assert_eq!(
2445                subgraph_builder.total_weight(),
2446                blossom_total_weight,
2447                "unexpected final dual variable sum"
2448            );
2449        }
2450        assert_eq!(
2451            interface_ptr.sum_dual_variables(),
2452            blossom_total_weight,
2453            "unexpected final dual variable sum"
2454        );
2455    }
2456
2457    /// debug a case of being stuck after disable the flag `debug_resolve_only_one` for faster speed
2458    #[test]
2459    #[cfg(feature = "blossom_v")]
2460    fn primal_module_debug_5() {
2461        // cargo test primal_module_debug_5 -- --nocapture
2462        let visualize_filename = "primal_module_debug_5.json".to_string();
2463        let defect_vertices = vec![0, 1, 3, 8, 9];
2464        let max_half_weight = 500;
2465        let mut code = CodeCapacityRepetitionCode::new(11, 0.03, max_half_weight);
2466        let mut visualizer = Visualizer::new(
2467            Some(visualize_data_folder() + visualize_filename.as_str()),
2468            code.get_positions(),
2469            true,
2470        )
2471        .unwrap();
2472        print_visualize_link(visualize_filename.clone());
2473        let initializer = code.get_initializer();
2474        // blossom V ground truth
2475        let blossom_mwpm_result = blossom_v_mwpm(&initializer, &defect_vertices);
2476        let blossom_details = detailed_matching(&initializer, &defect_vertices, &blossom_mwpm_result);
2477        let mut blossom_total_weight = 0;
2478        for detail in blossom_details.iter() {
2479            println!("    {detail:?}");
2480            blossom_total_weight += detail.weight;
2481        }
2482        // create dual module
2483        let mut dual_module = DualModuleSerial::new_empty(&initializer);
2484        // create primal module
2485        let mut primal_module = PrimalModuleSerialPtr::new_empty(&initializer);
2486        // try to work on a simple syndrome
2487        code.set_defect_vertices(&defect_vertices);
2488        let interface_ptr = DualModuleInterfacePtr::new_empty();
2489        primal_module.solve_visualizer(&interface_ptr, &code.get_syndrome(), &mut dual_module, Some(&mut visualizer));
2490        let fusion_mwpm = primal_module.perfect_matching(&interface_ptr, &mut dual_module);
2491        let fusion_mwpm_result = fusion_mwpm.legacy_get_mwpm_result(defect_vertices.clone());
2492        let fusion_details = detailed_matching(&initializer, &defect_vertices, &fusion_mwpm_result);
2493        let mut fusion_total_weight = 0;
2494        for detail in fusion_details.iter() {
2495            println!("    {detail:?}");
2496            fusion_total_weight += detail.weight;
2497        }
2498        assert_eq!(
2499            fusion_total_weight, blossom_total_weight,
2500            "unexpected final dual variable sum"
2501        );
2502        {
2503            // also test subgraph builder
2504            let mut subgraph_builder = SubGraphBuilder::new(&initializer);
2505            subgraph_builder.load_perfect_matching(&fusion_mwpm);
2506            assert_eq!(
2507                subgraph_builder.total_weight(),
2508                blossom_total_weight,
2509                "unexpected final dual variable sum"
2510            );
2511        }
2512        assert_eq!(
2513            interface_ptr.sum_dual_variables(),
2514            blossom_total_weight,
2515            "unexpected final dual variable sum"
2516        );
2517    }
2518
2519    #[test]
2520    fn primal_module_serial_perfect_matching_1() {
2521        // cargo test primal_module_serial_perfect_matching_1 -- --nocapture
2522        let defect_vertices = vec![39, 51, 61, 62, 63, 64, 65, 75, 87, 67];
2523        let (interface_ptr, mut primal_module, mut dual_module) =
2524            primal_module_serial_basic_standard_syndrome_optional_viz(11, None, defect_vertices, 6);
2525        let intermediate_matching = primal_module.intermediate_matching(&interface_ptr, &mut dual_module);
2526        println!("intermediate_matching: {intermediate_matching:?}");
2527        let perfect_matching = primal_module.perfect_matching(&interface_ptr, &mut dual_module);
2528        println!("perfect_matching: {perfect_matching:?}");
2529    }
2530
2531    /// debug a case of non-zero weight given pure erasure
2532    #[test]
2533    #[cfg(feature = "blossom_v")]
2534    fn primal_module_debug_6() {
2535        // cargo test primal_module_debug_6 -- --nocapture
2536        let visualize_filename = "primal_module_debug_6.json".to_string();
2537        let defect_vertices = vec![13, 34, 87, 107, 276, 296];
2538        let erasures = [13, 33, 174, 516];
2539        let max_half_weight = 500;
2540        let mut code = CodeCapacityPlanarCode::new(19, 0., max_half_weight);
2541        code.set_erasure_probability(0.003);
2542        let mut visualizer = Visualizer::new(
2543            Some(visualize_data_folder() + visualize_filename.as_str()),
2544            code.get_positions(),
2545            true,
2546        )
2547        .unwrap();
2548        print_visualize_link(visualize_filename.clone());
2549        let mut initializer = code.get_initializer();
2550        for edge_index in erasures.iter() {
2551            let (vertex_idx_1, vertex_idx_2, _) = &initializer.weighted_edges[*edge_index];
2552            initializer.weighted_edges[*edge_index] = (*vertex_idx_1, *vertex_idx_2, 0);
2553        }
2554        // blossom V ground truth
2555        let blossom_mwpm_result = blossom_v_mwpm(&initializer, &defect_vertices);
2556        let blossom_details = detailed_matching(&initializer, &defect_vertices, &blossom_mwpm_result);
2557        let mut blossom_total_weight = 0;
2558        for detail in blossom_details.iter() {
2559            println!("    {detail:?}");
2560            blossom_total_weight += detail.weight;
2561        }
2562        // create dual module
2563        let mut dual_module = DualModuleSerial::new_empty(&initializer);
2564        // create primal module
2565        let mut primal_module = PrimalModuleSerialPtr::new_empty(&initializer);
2566        // try to work on a simple syndrome
2567        code.set_defect_vertices(&defect_vertices);
2568        let interface_ptr = DualModuleInterfacePtr::new_empty();
2569        primal_module.solve_visualizer(&interface_ptr, &code.get_syndrome(), &mut dual_module, Some(&mut visualizer));
2570        let fusion_mwpm = primal_module.perfect_matching(&interface_ptr, &mut dual_module);
2571        let fusion_mwpm_result = fusion_mwpm.legacy_get_mwpm_result(defect_vertices.clone());
2572        let fusion_details = detailed_matching(&initializer, &defect_vertices, &fusion_mwpm_result);
2573        let mut fusion_total_weight = 0;
2574        for detail in fusion_details.iter() {
2575            println!("    {detail:?}");
2576            fusion_total_weight += detail.weight;
2577        }
2578        assert_eq!(
2579            fusion_total_weight, blossom_total_weight,
2580            "unexpected final dual variable sum"
2581        );
2582        {
2583            // also test subgraph builder
2584            let mut subgraph_builder = SubGraphBuilder::new(&initializer);
2585            subgraph_builder.load_perfect_matching(&fusion_mwpm);
2586            assert_eq!(
2587                subgraph_builder.total_weight(),
2588                blossom_total_weight,
2589                "unexpected final dual variable sum"
2590            );
2591        }
2592        assert_eq!(
2593            interface_ptr.sum_dual_variables(),
2594            blossom_total_weight,
2595            "unexpected final dual variable sum"
2596        );
2597    }
2598
2599    /// debug panic after adding the feature of max_tree_size
2600    #[test]
2601    fn primal_module_debug_7() {
2602        // cargo test primal_module_debug_7 -- --nocapture
2603        let visualize_filename = "primal_module_debug_7.json".to_string();
2604        let defect_vertices = vec![10, 11, 19, 21, 29, 34, 37, 40, 43, 49, 50, 51, 53];
2605        let max_half_weight = 500;
2606        let mut code = CodeCapacityPlanarCode::new(7, 0.1, max_half_weight);
2607        let mut visualizer = Visualizer::new(
2608            Some(visualize_data_folder() + visualize_filename.as_str()),
2609            code.get_positions(),
2610            true,
2611        )
2612        .unwrap();
2613        print_visualize_link(visualize_filename.clone());
2614        let initializer = code.get_initializer();
2615        let mut dual_module = DualModuleSerial::new_empty(&initializer);
2616        let mut primal_module = PrimalModuleSerialPtr::new_empty(&initializer);
2617        code.set_defect_vertices(&defect_vertices);
2618        let interface_ptr = DualModuleInterfacePtr::new_empty();
2619        primal_module.solve_visualizer(&interface_ptr, &code.get_syndrome(), &mut dual_module, Some(&mut visualizer));
2620    }
2621}