use super::util::*;
use crate::derivative::Derivative;
use super::primal_module::*;
use super::visualize::*;
use super::dual_module::*;
use std::cmp::Ordering;
use super::pointers::*;
#[derive(Derivative)]
#[derivative(Debug)]
pub struct PrimalModuleSerial {
pub unit_index: usize,
pub nodes: Vec<Option<PrimalNodeInternalPtr>>,
pub nodes_length: usize,
pub is_fusion: bool,
pub possible_break: Vec<NodeIndex>,
pub debug_resolve_only_one: bool,
pub parent: Option<PrimalModuleSerialWeak>,
pub index_bias: NodeIndex,
pub children: Option<((PrimalModuleSerialWeak, NodeNum), (PrimalModuleSerialWeak, NodeNum))>,
}
pub type PrimalModuleSerialPtr = ArcManualSafeLock<PrimalModuleSerial>;
pub type PrimalModuleSerialWeak = WeakManualSafeLock<PrimalModuleSerial>;
impl std::fmt::Debug for PrimalModuleSerialPtr {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let interface = self.read_recursive();
write!(f, "{}", interface.unit_index)
}
}
impl std::fmt::Debug for PrimalModuleSerialWeak {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
self.upgrade_force().fmt(f)
}
}
#[derive(Derivative)]
#[derivative(Debug)]
pub struct AlternatingTreeNode {
pub root: PrimalNodeInternalWeak,
pub parent: Option<(PrimalNodeInternalWeak, DualNodeWeak)>,
pub children: Vec<(PrimalNodeInternalWeak, DualNodeWeak)>,
pub depth: usize,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MatchTarget {
Peer(PrimalNodeInternalWeak),
VirtualVertex(VertexIndex),
}
#[derive(Derivative)]
#[derivative(Debug)]
pub struct PrimalNodeInternal {
pub origin: DualNodeWeak,
pub index: NodeIndex,
pub tree_node: Option<AlternatingTreeNode>,
pub temporary_match: Option<(MatchTarget, DualNodeWeak)>,
pub belonging: PrimalModuleSerialWeak,
}
pub type PrimalNodeInternalPtr = ArcManualSafeLock<PrimalNodeInternal>;
pub type PrimalNodeInternalWeak = WeakManualSafeLock<PrimalNodeInternal>;
impl std::fmt::Debug for PrimalNodeInternalPtr {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
self.update(); let primal_node_internal = self.read_recursive();
write!(f, "{}", primal_node_internal.index)
}
}
impl std::fmt::Debug for PrimalNodeInternalWeak {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
self.upgrade_force().fmt(f)
}
}
impl PrimalNodeInternal {
pub fn is_free(&self) -> bool {
debug_assert!({
let origin_ptr = self.origin.upgrade_force();
let node = origin_ptr.read_recursive();
node.parent_blossom.is_none()
}, "do not call this function to a internal node, consider call PrimalModuleSerial::get_outer_node");
if self.tree_node.is_some() { return false } if self.temporary_match.is_some() { return false } true
}
pub fn change_sub_tree_root(&mut self, depth: usize, root: PrimalNodeInternalPtr) {
let tree_node = self.tree_node.as_mut().unwrap();
tree_node.depth = depth;
tree_node.root = root.downgrade();
for (child_weak, _) in tree_node.children.iter() {
let child_ptr = child_weak.upgrade_force();
lock_write!(child, child_ptr);
child.change_sub_tree_root(depth + 1, root.clone());
}
}
}
impl PrimalNodeInternalPtr {
pub fn update(&self) -> &Self {
let mut current_belonging = self.read_recursive().belonging.upgrade_force();
let mut bias = 0;
let mut node = self.write();
while current_belonging.read_recursive().parent.is_some() {
let belonging_module = current_belonging.read_recursive();
bias += belonging_module.index_bias;
let new_current_belonging = belonging_module.parent.clone().unwrap().upgrade_force();
drop(belonging_module);
current_belonging = new_current_belonging;
}
node.belonging = current_belonging.downgrade();
node.index += bias;
self
}
}
impl PrimalModuleImpl for PrimalModuleSerialPtr {
fn new_empty(_initializer: &SolverInitializer) -> Self {
Self::new_value(PrimalModuleSerial {
unit_index: 0, nodes: vec![],
nodes_length: 0,
is_fusion: false,
possible_break: vec![],
debug_resolve_only_one: false,
parent: None,
index_bias: 0,
children: None,
})
}
fn clear(&mut self) {
let mut module = self.write();
module.nodes_length = 0; module.possible_break.clear();
module.is_fusion = false;
module.parent = None;
module.index_bias = 0;
module.children = None;
}
fn load_defect_dual_node(&mut self, dual_node_ptr: &DualNodePtr) {
let belonging = self.downgrade();
let node = dual_node_ptr.read_recursive();
debug_assert!(matches!(node.class, DualNodeClass::DefectVertex{ .. }), "must load a fresh dual module interface, found a blossom");
let mut module = self.write();
let local_node_index = module.nodes_length;
let node_index = module.nodes_count();
debug_assert_eq!(node.index, node_index, "must load in order");
let primal_node_internal_ptr = if !module.is_fusion && local_node_index < module.nodes.len() && module.nodes[local_node_index].is_some() {
let node_ptr = module.nodes[local_node_index].take().unwrap();
let mut node = node_ptr.write();
node.origin = dual_node_ptr.downgrade();
node.index = node_index;
node.tree_node = None;
node.temporary_match = None;
node.belonging = belonging;
drop(node);
node_ptr
} else {
PrimalNodeInternalPtr::new_value(PrimalNodeInternal {
origin: dual_node_ptr.downgrade(),
index: node_index,
tree_node: None,
temporary_match: None,
belonging,
})
};
module.nodes_length += 1;
if module.nodes.len() < module.nodes_length {
module.nodes.push(None);
}
module.nodes[local_node_index] = Some(primal_node_internal_ptr);
}
#[allow(clippy::collapsible_else_if)]
fn resolve<D: DualModuleImpl>(&mut self, mut group_max_update_length: GroupMaxUpdateLength, interface_ptr: &DualModuleInterfacePtr, dual_module: &mut D) {
debug_assert!(!group_max_update_length.is_empty() && group_max_update_length.get_none_zero_growth().is_none());
let mut current_conflict_index = 0;
let debug_resolve_only_one = self.read_recursive().debug_resolve_only_one;
while let Some(conflict) = group_max_update_length.pop() {
current_conflict_index += 1;
if debug_resolve_only_one && current_conflict_index > 1 { break
}
match conflict {
MaxUpdateLength::Conflicting((node_ptr_1, touching_ptr_1), (node_ptr_2, touching_ptr_2)) => {
debug_assert!(node_ptr_1 != node_ptr_2, "one cannot conflict with itself, double check to avoid deadlock");
if self.get_primal_node_internal_ptr_option(&node_ptr_1).is_none() { continue } if self.get_primal_node_internal_ptr_option(&node_ptr_2).is_none() { continue } let primal_node_internal_ptr_1 = self.get_outer_node(self.get_primal_node_internal_ptr(&node_ptr_1));
let primal_node_internal_ptr_2 = self.get_outer_node(self.get_primal_node_internal_ptr(&node_ptr_2));
if primal_node_internal_ptr_1 == primal_node_internal_ptr_2 {
debug_assert!(current_conflict_index != 1, "the first conflict cannot be ignored, otherwise may cause hidden infinite loop");
continue }
let mut primal_node_internal_1 = primal_node_internal_ptr_1.write();
let mut primal_node_internal_2 = primal_node_internal_ptr_2.write();
let grow_state_1 = primal_node_internal_1.origin.upgrade_force().read_recursive().grow_state;
let grow_state_2 = primal_node_internal_2.origin.upgrade_force().read_recursive().grow_state;
if !grow_state_1.is_against(&grow_state_2) {
debug_assert!(current_conflict_index != 1, "the first conflict cannot be ignored, otherwise may cause hidden infinite loop");
continue }
let (free_1, free_2) = (primal_node_internal_1.is_free(), primal_node_internal_2.is_free());
if free_1 && free_2 {
primal_node_internal_1.temporary_match = Some((MatchTarget::Peer(primal_node_internal_ptr_2.downgrade()), touching_ptr_1.downgrade()));
primal_node_internal_2.temporary_match = Some((MatchTarget::Peer(primal_node_internal_ptr_1.downgrade()), touching_ptr_2.downgrade()));
interface_ptr.set_grow_state(&primal_node_internal_1.origin.upgrade_force(), DualNodeGrowState::Stay, dual_module);
interface_ptr.set_grow_state(&primal_node_internal_2.origin.upgrade_force(), DualNodeGrowState::Stay, dual_module);
continue
}
if (free_1 && primal_node_internal_2.temporary_match.is_some()) || (free_2 && primal_node_internal_1.temporary_match.is_some()) {
let (free_node_internal_ptr, free_touching_ptr, mut free_node_internal, matched_node_internal_ptr, matched_touching_ptr, mut matched_node_internal) = if free_1 {
(primal_node_internal_ptr_1.clone(), touching_ptr_1.clone(), primal_node_internal_1, primal_node_internal_ptr_2.clone(), touching_ptr_2.clone(), primal_node_internal_2)
} else {
(primal_node_internal_ptr_2.clone(), touching_ptr_2.clone(), primal_node_internal_2, primal_node_internal_ptr_1.clone(), touching_ptr_1.clone(), primal_node_internal_1)
};
let (match_target, matched_touching_grandson) = matched_node_internal.temporary_match.as_ref().unwrap().clone();
match &match_target {
MatchTarget::Peer(leaf_node_internal_weak) => {
let leaf_node_internal_ptr = leaf_node_internal_weak.upgrade_force();
let mut leaf_node_internal = leaf_node_internal_ptr.write();
free_node_internal.tree_node = Some(AlternatingTreeNode {
root: free_node_internal_ptr.downgrade(),
parent: None,
children: vec![(matched_node_internal_ptr.downgrade(), free_touching_ptr.downgrade())],
depth: 0,
});
matched_node_internal.tree_node = Some(AlternatingTreeNode {
root: free_node_internal_ptr.downgrade(),
parent: Some((free_node_internal_ptr.downgrade(), matched_touching_ptr.downgrade())),
children: vec![(leaf_node_internal_weak.clone(), matched_touching_grandson)],
depth: 1,
});
matched_node_internal.temporary_match = None;
leaf_node_internal.tree_node = Some(AlternatingTreeNode {
root: free_node_internal_ptr.downgrade(),
parent: Some((matched_node_internal_ptr.downgrade(), leaf_node_internal.temporary_match.as_ref().unwrap().1.clone())),
children: vec![],
depth: 2,
});
leaf_node_internal.temporary_match = None;
interface_ptr.set_grow_state(&free_node_internal.origin.upgrade_force(), DualNodeGrowState::Grow, dual_module);
interface_ptr.set_grow_state(&matched_node_internal.origin.upgrade_force(), DualNodeGrowState::Shrink, dual_module);
interface_ptr.set_grow_state(&leaf_node_internal.origin.upgrade_force(), DualNodeGrowState::Grow, dual_module);
continue
},
MatchTarget::VirtualVertex(_) => {
free_node_internal.temporary_match = Some((MatchTarget::Peer(matched_node_internal_ptr.downgrade()), free_touching_ptr.downgrade()));
matched_node_internal.temporary_match = Some((MatchTarget::Peer(free_node_internal_ptr.downgrade()), matched_touching_ptr.downgrade()));
interface_ptr.set_grow_state(&free_node_internal.origin.upgrade_force(), DualNodeGrowState::Stay, dual_module);
interface_ptr.set_grow_state(&matched_node_internal.origin.upgrade_force(), DualNodeGrowState::Stay, dual_module);
continue
}
}
}
if (free_1 && primal_node_internal_2.tree_node.is_some()) || (primal_node_internal_1.tree_node.is_some() && free_2) {
let (tree_node_internal_ptr, tree_touching_ptr, tree_node_internal, free_node_internal_ptr, free_touching_ptr, mut free_node_internal) =
if primal_node_internal_1.tree_node.is_some() {
(primal_node_internal_ptr_1.clone(), touching_ptr_1.clone(), primal_node_internal_1, primal_node_internal_ptr_2.clone(), touching_ptr_2.clone(), primal_node_internal_2)
} else {
(primal_node_internal_ptr_2.clone(), touching_ptr_2.clone(), primal_node_internal_2, primal_node_internal_ptr_1.clone(), touching_ptr_1.clone(), primal_node_internal_1)
};
free_node_internal.temporary_match = Some((MatchTarget::Peer(tree_node_internal_ptr.downgrade()), free_touching_ptr.downgrade()));
interface_ptr.set_grow_state(&free_node_internal.origin.upgrade_force(), DualNodeGrowState::Stay, dual_module);
drop(tree_node_internal); Self::augment_tree_given_matched(tree_node_internal_ptr, free_node_internal_ptr, tree_touching_ptr.downgrade(), interface_ptr, dual_module);
continue
}
if (primal_node_internal_1.tree_node.is_some() && primal_node_internal_2.temporary_match.is_some())
|| (primal_node_internal_1.temporary_match.is_some() && primal_node_internal_2.tree_node.is_some()) {
let (tree_node_internal_ptr, tree_touching_ptr, mut tree_node_internal, matched_node_internal_ptr, matched_touching_ptr, mut matched_node_internal) =
if primal_node_internal_1.tree_node.is_some() {
(primal_node_internal_ptr_1.clone(), touching_ptr_1.clone(), primal_node_internal_1, primal_node_internal_ptr_2.clone(), touching_ptr_2.clone(), primal_node_internal_2)
} else {
(primal_node_internal_ptr_2.clone(), touching_ptr_2.clone(), primal_node_internal_2, primal_node_internal_ptr_1.clone(), touching_ptr_1.clone(), primal_node_internal_1)
};
let match_target = matched_node_internal.temporary_match.as_ref().unwrap().0.clone();
match &match_target {
MatchTarget::Peer(leaf_node_internal_weak) => {
let leaf_node_internal_ptr = leaf_node_internal_weak.upgrade_force();
let tree_node = tree_node_internal.tree_node.as_mut().unwrap();
debug_assert!(tree_node.depth % 2 == 0, "conflicting one must be + node");
tree_node.children.push((matched_node_internal_ptr.downgrade(), tree_touching_ptr.downgrade()));
matched_node_internal.tree_node = Some(AlternatingTreeNode {
root: tree_node.root.clone(),
parent: Some((tree_node_internal_ptr.downgrade(), matched_touching_ptr.downgrade())),
children: vec![(leaf_node_internal_weak.clone(), matched_node_internal.temporary_match.as_ref().unwrap().1.clone())],
depth: tree_node.depth + 1,
});
matched_node_internal.temporary_match = None;
let mut leaf_node_internal = leaf_node_internal_ptr.write();
leaf_node_internal.tree_node = Some(AlternatingTreeNode {
root: tree_node.root.clone(),
parent: Some((matched_node_internal_ptr.downgrade(), leaf_node_internal.temporary_match.as_ref().unwrap().1.clone())),
children: vec![],
depth: tree_node.depth + 2,
});
leaf_node_internal.temporary_match = None;
interface_ptr.set_grow_state(&matched_node_internal.origin.upgrade_force(), DualNodeGrowState::Shrink, dual_module);
interface_ptr.set_grow_state(&leaf_node_internal.origin.upgrade_force(), DualNodeGrowState::Grow, dual_module);
continue
},
MatchTarget::VirtualVertex(_) => {
matched_node_internal.temporary_match = Some((MatchTarget::Peer(tree_node_internal_ptr.downgrade()), matched_touching_ptr.downgrade()));
drop(matched_node_internal); drop(tree_node_internal); Self::augment_tree_given_matched(tree_node_internal_ptr, matched_node_internal_ptr, tree_touching_ptr.downgrade(), interface_ptr, dual_module);
continue
}
}
}
if primal_node_internal_1.tree_node.is_some() && primal_node_internal_2.tree_node.is_some() {
let root_1 = primal_node_internal_1.tree_node.as_ref().unwrap().root.clone();
let root_2 = primal_node_internal_2.tree_node.as_ref().unwrap().root.clone();
if root_1 == root_2 {
drop(primal_node_internal_1);
drop(primal_node_internal_2);
let (lca_ptr, path_1, path_2) = self.find_lowest_common_ancestor(primal_node_internal_ptr_1.clone(), primal_node_internal_ptr_2.clone());
let nodes_circle = {
let mut nodes_circle: Vec<DualNodePtr> = path_1.iter().map(|ptr| ptr.read_recursive().origin.upgrade_force()).collect();
nodes_circle.push(lca_ptr.read_recursive().origin.upgrade_force());
for i in (0..path_2.len()).rev() { nodes_circle.push(path_2[i].read_recursive().origin.upgrade_force()); }
nodes_circle
};
let touching_children = {
let mut touching_children = Vec::<(DualNodeWeak, DualNodeWeak)>::new();
if !path_1.is_empty() {
for (idx, ptr) in path_1.iter().enumerate() {
let node = ptr.read_recursive();
let tree_node = node.tree_node.as_ref().unwrap();
let left_touching_ptr = if idx == 0 {
touching_ptr_1.downgrade()
} else {
let last_ptr = path_1[idx-1].downgrade();
let idx = tree_node.children.iter().position(|(ptr, _)| ptr == &last_ptr).expect("should find child");
tree_node.children[idx].1.clone()
};
let right_touching_ptr = tree_node.parent.as_ref().unwrap().1.clone();
touching_children.push((left_touching_ptr, right_touching_ptr));
}
}
{ let node = lca_ptr.read_recursive();
let tree_node = node.tree_node.as_ref().unwrap();
let left_touching_ptr = if path_1.is_empty() {
touching_ptr_1.downgrade()
} else {
let left_ptr = path_1[path_1.len() - 1].downgrade();
let left_idx = tree_node.children.iter().position(|(ptr, _)| ptr == &left_ptr).expect("should find child");
tree_node.children[left_idx].1.clone()
};
let right_touching_ptr = if path_2.is_empty() {
touching_ptr_2.downgrade()
} else {
let right_ptr = path_2[path_2.len() - 1].downgrade();
let right_idx = tree_node.children.iter().position(|(ptr, _)| ptr == &right_ptr).expect("should find child");
tree_node.children[right_idx].1.clone()
};
touching_children.push((left_touching_ptr, right_touching_ptr));
}
if !path_2.is_empty() {
for (idx, ptr) in path_2.iter().enumerate().rev() {
let node = ptr.read_recursive();
let tree_node = node.tree_node.as_ref().unwrap();
let left_touching_ptr = tree_node.parent.as_ref().unwrap().1.clone();
let right_touching_ptr = if idx == 0 {
touching_ptr_2.downgrade()
} else {
let last_ptr = path_2[idx-1].downgrade();
let idx = tree_node.children.iter().position(|(ptr, _)| ptr == &last_ptr).expect("should find child");
tree_node.children[idx].1.clone()
};
touching_children.push((left_touching_ptr, right_touching_ptr));
}
}
touching_children
};
let blossom_node_ptr = interface_ptr.create_blossom(nodes_circle, touching_children, dual_module);
let primal_node_internal_blossom_ptr = { let belonging = self.downgrade();
let mut module = self.write();
let local_node_index = module.nodes_length;
let node_index = module.nodes_count();
let primal_node_internal_blossom_ptr = if !module.is_fusion && local_node_index < module.nodes.len() && module.nodes[local_node_index].is_some() {
let node_ptr = module.nodes[local_node_index].take().unwrap();
let mut node = node_ptr.write();
node.origin = blossom_node_ptr.downgrade();
node.index = node_index;
node.tree_node = None;
node.temporary_match = None;
node.belonging = belonging;
drop(node);
node_ptr
} else {
PrimalNodeInternalPtr::new_value(PrimalNodeInternal {
origin: blossom_node_ptr.downgrade(),
index: node_index,
tree_node: None,
temporary_match: None,
belonging,
})
};
module.nodes_length += 1;
if module.nodes.len() < module.nodes_length {
module.nodes.push(None);
}
let cloned_primal_node_internal_blossom_ptr = primal_node_internal_blossom_ptr.clone();
module.nodes[local_node_index] = Some(primal_node_internal_blossom_ptr); cloned_primal_node_internal_blossom_ptr
};
let mut children = vec![];
for path in [&path_1, &path_2] {
if !path.is_empty() {
let mut last_ptr = path[0].downgrade();
for (height, ptr) in path.iter().enumerate() {
let mut node = ptr.write();
if height == 0 {
let tree_node = node.tree_node.as_ref().unwrap();
for (child_ptr, child_touching_ptr) in tree_node.children.iter() {
children.push((child_ptr.clone(), child_touching_ptr.clone()));
}
} else {
if height % 2 == 0 {
let tree_node = node.tree_node.as_ref().unwrap();
for (child_ptr, child_touching_ptr) in tree_node.children.iter() {
if child_ptr != &last_ptr { children.push((child_ptr.clone(), child_touching_ptr.clone()));
}
}
}
}
node.tree_node = None; last_ptr = ptr.downgrade();
}
}
}
let mut lca = lca_ptr.write();
let lca_tree_node = lca.tree_node.as_ref().unwrap();
{ for (child_ptr, child_touching_ptr) in lca_tree_node.children.iter() {
if !path_1.is_empty() && &path_1[path_1.len() - 1].downgrade() == child_ptr { continue }
if !path_2.is_empty() && &path_2[path_2.len() - 1].downgrade() == child_ptr { continue }
children.push((child_ptr.clone(), child_touching_ptr.clone()));
}
}
if lca_tree_node.parent.is_some() || !children.is_empty() {
let mut primal_node_internal_blossom = primal_node_internal_blossom_ptr.write();
let new_tree_root = if lca_tree_node.depth == 0 { primal_node_internal_blossom_ptr.clone() } else { lca_tree_node.root.upgrade_force() };
let tree_node = AlternatingTreeNode {
root: new_tree_root.downgrade(),
parent: lca_tree_node.parent.clone(),
children,
depth: lca_tree_node.depth,
};
if lca_tree_node.parent.is_some() {
let (parent_weak, _) = lca_tree_node.parent.as_ref().unwrap();
let parent_ptr = parent_weak.upgrade_force();
lock_write!(parent, parent_ptr);
let parent_tree_node = parent.tree_node.as_mut().unwrap();
debug_assert!(parent_tree_node.children.len() == 1, "lca's parent should be a - node with only one child");
let touching_ptr = parent_tree_node.children[0].1.clone(); parent_tree_node.children.clear();
parent_tree_node.children.push((primal_node_internal_blossom_ptr.downgrade(), touching_ptr));
}
if !tree_node.children.is_empty() {
for (child_weak, _) in tree_node.children.iter() {
let child_ptr = child_weak.upgrade_force();
lock_write!(child, child_ptr);
let child_tree_node = child.tree_node.as_mut().unwrap();
debug_assert!(child_tree_node.parent.is_some(), "child should have a parent");
let touching_ptr = child_tree_node.parent.as_ref().unwrap().1.clone(); child_tree_node.parent = Some((primal_node_internal_blossom_ptr.downgrade(), touching_ptr));
}
primal_node_internal_blossom.tree_node = Some(tree_node);
primal_node_internal_blossom.change_sub_tree_root(lca_tree_node.depth, new_tree_root);
} else {
primal_node_internal_blossom.tree_node = Some(tree_node);
}
}
lca.tree_node = None;
continue
} else {
drop(primal_node_internal_1); drop(primal_node_internal_2); Self::augment_tree_given_matched(primal_node_internal_ptr_1.clone(), primal_node_internal_ptr_2.clone(), touching_ptr_1.downgrade()
, interface_ptr, dual_module);
Self::augment_tree_given_matched(primal_node_internal_ptr_2.clone(), primal_node_internal_ptr_1.clone(), touching_ptr_2.downgrade()
, interface_ptr, dual_module);
continue
}
}
unreachable!()
},
MaxUpdateLength::TouchingVirtual((node_ptr, touching_ptr), (virtual_vertex_index, is_mirror)) => {
if self.get_primal_node_internal_ptr_option(&node_ptr).is_none() { continue } let primal_node_internal_ptr = self.get_outer_node(self.get_primal_node_internal_ptr(&node_ptr));
let mut primal_node_internal = primal_node_internal_ptr.write();
let grow_state = primal_node_internal.origin.upgrade_force().read_recursive().grow_state;
if grow_state != DualNodeGrowState::Grow {
debug_assert!(current_conflict_index != 1, "the first conflict cannot be ignored, otherwise may cause hidden infinite loop");
continue }
if primal_node_internal.is_free() {
primal_node_internal.temporary_match = Some((MatchTarget::VirtualVertex(virtual_vertex_index), touching_ptr.downgrade()));
if is_mirror {
lock_write!(module, self);
module.possible_break.push(primal_node_internal.index);
}
interface_ptr.set_grow_state(&primal_node_internal.origin.upgrade_force(), DualNodeGrowState::Stay, dual_module);
continue
}
if primal_node_internal.tree_node.is_some() {
if is_mirror {
lock_write!(module, self);
module.possible_break.push(primal_node_internal.index);
}
drop(primal_node_internal);
self.augment_tree_given_virtual_vertex(primal_node_internal_ptr, virtual_vertex_index, touching_ptr.downgrade(), interface_ptr, dual_module);
continue
}
unreachable!()
},
MaxUpdateLength::BlossomNeedExpand(node_ptr) => {
if self.get_primal_node_internal_ptr_option(&node_ptr).is_none() { continue } let primal_node_internal_ptr = self.get_primal_node_internal_ptr(&node_ptr);
let outer_primal_node_internal_ptr = self.get_outer_node(primal_node_internal_ptr.clone());
if outer_primal_node_internal_ptr != primal_node_internal_ptr {
debug_assert!(current_conflict_index != 1, "the first conflict cannot be ignored, otherwise may cause hidden infinite loop");
continue
}
let primal_node_internal = primal_node_internal_ptr.read_recursive();
let grow_state = primal_node_internal.origin.upgrade_force().read_recursive().grow_state;
if grow_state != DualNodeGrowState::Shrink {
debug_assert!(current_conflict_index != 1, "the first conflict cannot be ignored, otherwise may cause hidden infinite loop");
continue }
let (nodes_circle, touching_children) = {
let blossom = node_ptr.read_recursive();
match &blossom.class {
DualNodeClass::Blossom{ nodes_circle, touching_children } => (nodes_circle.clone(), touching_children.clone()),
_ => unreachable!("the expanding node is not a blossom")
}
};
debug_assert!(primal_node_internal.tree_node.is_some(), "expanding blossom must belong to an alternating tree");
let tree_node = primal_node_internal.tree_node.as_ref().unwrap();
debug_assert!(tree_node.depth % 2 == 1, "expanding blossom must a '-' node in an alternating tree");
let (parent_ptr, parent_touching_ptr, parent_touching_child_ptr) = { let (parent_weak, parent_touching_child_ptr) = &tree_node.parent.as_ref().unwrap();
let parent_ptr = parent_weak.upgrade_force();
lock_write!(parent, parent_ptr);
let parent_tree_node = parent.tree_node.as_mut().unwrap();
let idx = parent_tree_node.children.iter().position(|ptr| ptr.0 == primal_node_internal_ptr.downgrade()).expect("should find");
let parent_touching_ptr = parent_tree_node.children[idx].1.clone();
parent_tree_node.children.remove(idx);
parent_tree_node.children.retain(|ptr| ptr.0 != primal_node_internal_ptr.downgrade());
(parent_ptr.clone(), parent_touching_ptr, parent_touching_child_ptr.upgrade_force().get_secondary_ancestor_blossom().downgrade())
};
let (child_ptr, child_touching_ptr, child_touching_child_ptr) = { debug_assert!(tree_node.children.len() == 1, "a - node must have exactly ONE child");
let child_weak = &tree_node.children[0].0;
let child_touching_child_ptr = tree_node.children[0].1.upgrade_force().get_secondary_ancestor_blossom().downgrade();
let child_ptr = child_weak.upgrade_force();
let child = child_ptr.read_recursive();
let child_tree_node = child.tree_node.as_ref().unwrap();
(child_ptr.clone(), child_tree_node.parent.as_ref().unwrap().1.clone(), child_touching_child_ptr)
};
interface_ptr.expand_blossom(node_ptr, dual_module);
let parent_touching_index = nodes_circle.iter().position(|ptr| ptr == &parent_touching_child_ptr).expect("touching node should be in the blossom circle");
let child_touching_index = nodes_circle.iter().position(|ptr| ptr == &child_touching_child_ptr).expect("touching node should be in the blossom circle");
let mut is_tree_sequence_ascending = true;
let (match_sequence, tree_sequence) = { let mut match_sequence = Vec::new();
let mut tree_sequence = Vec::new();
match parent_touching_index.cmp(&child_touching_index) {
Ordering::Equal => {
tree_sequence.push(parent_touching_index);
for i in parent_touching_index+1 .. nodes_circle.len() { match_sequence.push(i); }
for i in 0 .. parent_touching_index { match_sequence.push(i); }
},
Ordering::Greater => {
if (parent_touching_index - child_touching_index) % 2 == 0 { for i in (child_touching_index .. parent_touching_index+1).rev() { tree_sequence.push(i); }
is_tree_sequence_ascending = false;
for i in parent_touching_index+1 .. nodes_circle.len() { match_sequence.push(i); }
for i in 0 .. child_touching_index { match_sequence.push(i); }
} else { for i in parent_touching_index .. nodes_circle.len() { tree_sequence.push(i); }
for i in 0 .. child_touching_index+1 { tree_sequence.push(i); }
for i in child_touching_index+1 .. parent_touching_index { match_sequence.push(i); }
}
},
Ordering::Less => {
if (child_touching_index - parent_touching_index) % 2 == 0 { for i in parent_touching_index .. child_touching_index+1 { tree_sequence.push(i); }
for i in child_touching_index+1 .. nodes_circle.len() { match_sequence.push(i); }
for i in 0 .. parent_touching_index { match_sequence.push(i); }
} else { for i in (0 .. parent_touching_index+1).rev() { tree_sequence.push(i); }
for i in (child_touching_index .. nodes_circle.len()).rev() { tree_sequence.push(i); }
is_tree_sequence_ascending = false;
for i in parent_touching_index+1 .. child_touching_index { match_sequence.push(i); }
}
},
}
(match_sequence, tree_sequence)
};
debug_assert!(match_sequence.len() % 2 == 0 && tree_sequence.len() % 2 == 1, "parity of sequence wrong");
for i in (0..match_sequence.len()).step_by(2) {
let primal_node_internal_ptr_1 = self.get_primal_node_internal_ptr(&nodes_circle[match_sequence[i]].upgrade_force());
let primal_node_internal_ptr_2 = self.get_primal_node_internal_ptr(&nodes_circle[match_sequence[i+1]].upgrade_force());
debug_assert!((match_sequence[i] + 1) % nodes_circle.len() == match_sequence[i+1], "match sequence should be ascending");
let touching_ptr_1 = touching_children[match_sequence[i]].1.clone(); let touching_ptr_2 = touching_children[match_sequence[i+1]].0.clone(); let mut primal_node_internal_1 = primal_node_internal_ptr_1.write();
let mut primal_node_internal_2 = primal_node_internal_ptr_2.write();
primal_node_internal_1.temporary_match = Some((MatchTarget::Peer(primal_node_internal_ptr_2.downgrade()), touching_ptr_1));
primal_node_internal_2.temporary_match = Some((MatchTarget::Peer(primal_node_internal_ptr_1.downgrade()), touching_ptr_2));
interface_ptr.set_grow_state(&primal_node_internal_1.origin.upgrade_force(), DualNodeGrowState::Stay, dual_module);
interface_ptr.set_grow_state(&primal_node_internal_2.origin.upgrade_force(), DualNodeGrowState::Stay, dual_module);
}
for (idx, current_i) in tree_sequence.iter().enumerate() {
debug_assert!({
if idx + 1 < tree_sequence.len() {
if is_tree_sequence_ascending { (tree_sequence[idx] + 1) % nodes_circle.len() == tree_sequence[idx+1] }
else { (tree_sequence[idx+1] + 1) % nodes_circle.len() == tree_sequence[idx] }
} else { true }
}, "tree sequence orientation must be consistent");
let current_parent_ptr = if idx == 0 { parent_ptr.clone() } else { self.get_primal_node_internal_ptr(&nodes_circle[tree_sequence[idx - 1]].upgrade_force()) };
let current_parent_touching_ptr = if idx == 0 {
tree_node.parent.as_ref().unwrap().1.clone()
} else {
if is_tree_sequence_ascending { touching_children[*current_i].0.clone() } else { touching_children[*current_i].1.clone() }
};
let current_child_ptr = if idx == tree_sequence.len() - 1 { child_ptr.clone() }
else { self.get_primal_node_internal_ptr(&nodes_circle[tree_sequence[idx + 1]].upgrade_force()) };
let current_child_touching_ptr = if idx == tree_sequence.len() - 1 {
tree_node.children[0].1.clone()
} else {
if is_tree_sequence_ascending { touching_children[*current_i].1.clone() } else { touching_children[*current_i].0.clone() }
};
let current_ptr = self.get_primal_node_internal_ptr(&nodes_circle[*current_i].upgrade_force());
let mut current = current_ptr.write();
current.tree_node = Some(AlternatingTreeNode {
root: tree_node.root.clone(),
parent: Some((current_parent_ptr.downgrade(), current_parent_touching_ptr)),
children: vec![(current_child_ptr.downgrade(), current_child_touching_ptr)],
depth: tree_node.depth + idx,
});
interface_ptr.set_grow_state(¤t.origin.upgrade_force(), if idx % 2 == 0 { DualNodeGrowState::Shrink } else { DualNodeGrowState::Grow }, dual_module);
}
{ lock_write!(parent, parent_ptr);
let parent_tree_node = parent.tree_node.as_mut().unwrap();
let child_ptr = self.get_primal_node_internal_ptr(&nodes_circle[tree_sequence[0]].upgrade_force());
parent_tree_node.children.push((child_ptr.downgrade(), parent_touching_ptr));
}
{ lock_write!(child, child_ptr);
let child_tree_node = child.tree_node.as_mut().unwrap();
let parent_ptr = self.get_primal_node_internal_ptr(&nodes_circle[tree_sequence[tree_sequence.len()-1]].upgrade_force());
child_tree_node.parent = Some((parent_ptr.downgrade(), child_touching_ptr));
child.change_sub_tree_root(tree_node.depth + tree_sequence.len(), tree_node.root.upgrade_force());
}
{ lock_write!(module, self);
debug_assert_eq!(module.get_node(primal_node_internal.index), Some(primal_node_internal_ptr.clone()), "index wrong");
module.remove_node(primal_node_internal.index);
}
},
MaxUpdateLength::VertexShrinkStop(_node_ptr) => {
if current_conflict_index == 1 {
unreachable!("VertexShrinkStop conflict cannot be solved by primal module, and should be sorted to the last of the heap")
}
}
_ => unreachable!("should not resolve these issues")
}
}
}
fn intermediate_matching<D: DualModuleImpl>(&mut self, _interface: &DualModuleInterfacePtr, _dual_module: &mut D) -> IntermediateMatching {
let mut immediate_matching = IntermediateMatching::new();
let mut flattened_nodes = vec![];
self.flatten_nodes(&mut flattened_nodes);
for primal_node_internal_ptr in flattened_nodes.iter().flatten() {
let primal_node_internal = primal_node_internal_ptr.read_recursive();
debug_assert!(primal_node_internal.tree_node.is_none(), "cannot compute perfect matching with active alternating tree");
let origin_ptr = primal_node_internal.origin.upgrade_force();
let interface_node = origin_ptr.read_recursive();
if interface_node.parent_blossom.is_some() {
debug_assert_eq!(primal_node_internal.temporary_match, None, "blossom internal nodes should not be matched");
continue }
if let Some((match_target, match_touching_ptr)) = primal_node_internal.temporary_match.as_ref() {
match match_target {
MatchTarget::Peer(peer_internal_weak) => {
let peer_internal_ptr = peer_internal_weak.upgrade_force();
let peer_internal = peer_internal_ptr.read_recursive();
if primal_node_internal.index < peer_internal.index { let peer_touching_ptr = peer_internal.temporary_match.as_ref().unwrap().1.clone();
immediate_matching.peer_matchings.push((
(primal_node_internal.origin.upgrade_force(), match_touching_ptr.clone()),
(peer_internal.origin.upgrade_force(), peer_touching_ptr)
));
}
},
MatchTarget::VirtualVertex(virtual_vertex) => {
immediate_matching.virtual_matchings.push((
(primal_node_internal.origin.upgrade_force(), match_touching_ptr.clone())
, *virtual_vertex
));
},
}
} else {
panic!("cannot compute final matching with unmatched outer node {:?}", primal_node_internal_ptr);
}
}
immediate_matching
}
}
impl FusionVisualizer for PrimalModuleSerialPtr {
fn snapshot(&self, abbrev: bool) -> serde_json::Value {
let flattened_nodes = self.sanity_check().unwrap();
let mut primal_nodes = Vec::<serde_json::Value>::new();
for primal_node_ptr in flattened_nodes.iter() {
if let Some(primal_node_ptr) = &primal_node_ptr {
let primal_node = primal_node_ptr.read_recursive();
primal_nodes.push(json!({
if abbrev { "m" } else { "temporary_match" }: primal_node.temporary_match.as_ref().map(|(match_target, touching_ptr)| {
match match_target {
MatchTarget::Peer(peer_weak) => {
let peer_ptr = peer_weak.upgrade_force();
json!({
if abbrev { "p" } else { "peer" }: peer_ptr.read_recursive().index,
if abbrev { "t" } else { "touching" }: touching_ptr.upgrade_force().read_recursive().index,
})
},
MatchTarget::VirtualVertex(vertex_idx) => json!({
if abbrev { "v" } else { "virtual_vertex" }: vertex_idx,
if abbrev { "t" } else { "touching" }: touching_ptr.upgrade_force().read_recursive().index,
}),
}
}),
if abbrev { "t" } else { "tree_node" }: primal_node.tree_node.as_ref().map(|tree_node| {
json!({
if abbrev { "r" } else { "root" }: tree_node.root.upgrade_force().read_recursive().index,
if abbrev { "p" } else { "parent" }: tree_node.parent.as_ref().map(|(weak, _)| weak.upgrade_force().read_recursive().index),
if abbrev { "pt" } else { "parent_touching" }: tree_node.parent.as_ref().map(|(_, weak)| weak.upgrade_force().read_recursive().index),
if abbrev { "c" } else { "children" }: tree_node.children.iter().map(|(weak, _)| weak.upgrade_force().read_recursive().index).collect::<Vec<NodeIndex>>(),
if abbrev { "ct" } else { "children_touching" }: tree_node.children.iter().map(|(_, weak)| weak.upgrade_force().read_recursive().index).collect::<Vec<NodeIndex>>(),
if abbrev { "d" } else { "depth" }: tree_node.depth,
})
}),
}));
} else {
primal_nodes.push(json!(null));
}
}
json!({
"primal_nodes": primal_nodes,
})
}
}
impl PrimalModuleSerial {
pub fn nodes_count(&self) -> NodeNum {
let mut count = self.nodes_length as NodeNum;
if let Some(((_, left_count), (_, right_count))) = &self.children {
count += left_count + right_count;
}
count
}
pub fn get_node(&self, relative_node_index: NodeIndex) -> Option<PrimalNodeInternalPtr> {
debug_assert!(relative_node_index < self.nodes_count(), "cannot find node in this module");
let mut bias = 0;
if let Some(((left_weak, left_count), (right_weak, right_count))) = &self.children {
if relative_node_index < *left_count {
return left_weak.upgrade_force().read_recursive().get_node(relative_node_index);
} else if relative_node_index < *left_count + *right_count {
return right_weak.upgrade_force().read_recursive().get_node(relative_node_index - *left_count);
}
bias = left_count + right_count;
}
self.nodes[(relative_node_index - bias) as usize].clone()
}
pub fn remove_node(&mut self, relative_node_index: NodeIndex) {
debug_assert!(relative_node_index < self.nodes_count(), "cannot find node in this module");
let mut bias = 0;
if let Some(((left_weak, left_count), (right_weak, right_count))) = &self.children {
if relative_node_index < *left_count {
left_weak.upgrade_force().write().remove_node(relative_node_index);
return
} else if relative_node_index < *left_count + *right_count {
right_weak.upgrade_force().write().remove_node(relative_node_index - *left_count);
return
}
bias = left_count + right_count;
}
self.nodes[(relative_node_index - bias) as usize] = None;
}
}
impl PrimalModuleSerialPtr {
pub fn get_primal_node_internal_ptr_option(&self, dual_node_ptr: &DualNodePtr) -> Option<PrimalNodeInternalPtr> {
let module = self.read_recursive();
let dual_node = dual_node_ptr.read_recursive();
let primal_node_internal_ptr = module.get_node(dual_node.index);
if let Some(primal_node_internal_ptr) = &primal_node_internal_ptr {
if module.is_fusion {
primal_node_internal_ptr.update(); }
debug_assert!(dual_node_ptr == &primal_node_internal_ptr.read_recursive().origin.upgrade_force()
, "dual node and primal internal node must corresponds to each other");
}
primal_node_internal_ptr
}
pub fn get_primal_node_internal_ptr(&self, dual_node_ptr: &DualNodePtr) -> PrimalNodeInternalPtr {
self.get_primal_node_internal_ptr_option(dual_node_ptr).expect("internal primal node must exists")
}
pub fn get_outer_node(&self, primal_node_internal_ptr: PrimalNodeInternalPtr) -> PrimalNodeInternalPtr {
let node = primal_node_internal_ptr.read_recursive();
let origin_ptr = node.origin.upgrade_force();
let interface_node = origin_ptr.read_recursive();
if let Some(parent_dual_node_weak) = &interface_node.parent_blossom {
let parent_dual_node_ptr = parent_dual_node_weak.upgrade_force();
let parent_primal_node_internal_ptr = self.get_primal_node_internal_ptr(&parent_dual_node_ptr);
self.get_outer_node(parent_primal_node_internal_ptr)
} else {
primal_node_internal_ptr.clone()
}
}
pub fn find_lowest_common_ancestor(&self, mut primal_node_internal_ptr_1: PrimalNodeInternalPtr, mut primal_node_internal_ptr_2: PrimalNodeInternalPtr)
-> (PrimalNodeInternalPtr, Vec<PrimalNodeInternalPtr>, Vec<PrimalNodeInternalPtr>) {
let (depth_1, depth_2) = {
let primal_node_internal_1 = primal_node_internal_ptr_1.read_recursive();
let primal_node_internal_2 = primal_node_internal_ptr_2.read_recursive();
let tree_node_1 = primal_node_internal_1.tree_node.as_ref().unwrap();
let tree_node_2 = primal_node_internal_2.tree_node.as_ref().unwrap();
debug_assert_eq!(tree_node_1.root, tree_node_2.root, "must belong to the same tree");
(tree_node_1.depth, tree_node_2.depth)
};
let mut path_1 = vec![];
let mut path_2 = vec![];
match depth_1.cmp(&depth_2) {
Ordering::Greater => {
loop {
let ptr = primal_node_internal_ptr_1.clone();
let primal_node_internal = ptr.read_recursive();
let tree_node = primal_node_internal.tree_node.as_ref().unwrap();
if tree_node.depth == depth_2 { break }
path_1.push(primal_node_internal_ptr_1.clone());
primal_node_internal_ptr_1 = tree_node.parent.as_ref().unwrap().0.upgrade_force();
}
},
Ordering::Less => {
loop {
let ptr = primal_node_internal_ptr_2.clone();
let primal_node_internal = ptr.read_recursive();
let tree_node = primal_node_internal.tree_node.as_ref().unwrap();
if tree_node.depth == depth_1 { break }
path_2.push(primal_node_internal_ptr_2.clone());
primal_node_internal_ptr_2 = tree_node.parent.as_ref().unwrap().0.upgrade_force();
}
},
Ordering::Equal => { }
}
loop {
if primal_node_internal_ptr_1 == primal_node_internal_ptr_2 {
return (primal_node_internal_ptr_1, path_1, path_2)
}
let ptr_1 = primal_node_internal_ptr_1.clone();
let ptr_2 = primal_node_internal_ptr_2.clone();
let primal_node_internal_1 = ptr_1.read_recursive();
let primal_node_internal_2 = ptr_2.read_recursive();
let tree_node_1 = primal_node_internal_1.tree_node.as_ref().unwrap();
let tree_node_2 = primal_node_internal_2.tree_node.as_ref().unwrap();
path_1.push(primal_node_internal_ptr_1.clone());
path_2.push(primal_node_internal_ptr_2.clone());
primal_node_internal_ptr_1 = tree_node_1.parent.as_ref().unwrap().0.upgrade_force();
primal_node_internal_ptr_2 = tree_node_2.parent.as_ref().unwrap().0.upgrade_force();
}
}
pub fn match_subtree<D: DualModuleImpl>(tree_node_internal_ptr: PrimalNodeInternalPtr, interface_ptr: &DualModuleInterfacePtr, dual_module: &mut D) {
let mut tree_node_internal = tree_node_internal_ptr.write();
let tree_node = tree_node_internal.tree_node.as_ref().unwrap();
debug_assert!(tree_node.depth % 2 == 1, "only match - node is possible");
let child_node_internal_ptr = tree_node.children[0].0.upgrade_force();
tree_node_internal.temporary_match = Some((MatchTarget::Peer(child_node_internal_ptr.downgrade()), tree_node.children[0].1.clone()));
interface_ptr.set_grow_state(&tree_node_internal.origin.upgrade_force(), DualNodeGrowState::Stay, dual_module);
tree_node_internal.tree_node = None;
let mut child_node_internal = child_node_internal_ptr.write();
let child_touching_ptr = child_node_internal.tree_node.as_ref().unwrap().parent.as_ref().unwrap().1.clone();
child_node_internal.temporary_match = Some((MatchTarget::Peer(tree_node_internal_ptr.downgrade()), child_touching_ptr));
let child_tree_node = child_node_internal.tree_node.as_ref().unwrap();
interface_ptr.set_grow_state(&child_node_internal.origin.upgrade_force(), DualNodeGrowState::Stay, dual_module);
for (grandson_ptr, _) in child_tree_node.children.iter() {
Self::match_subtree(grandson_ptr.upgrade_force(), interface_ptr, dual_module);
}
child_node_internal.tree_node = None;
}
pub fn augment_tree_given_matched<D: DualModuleImpl>(tree_node_internal_ptr: PrimalNodeInternalPtr, match_node_internal_ptr: PrimalNodeInternalPtr
, tree_touching_ptr: DualNodeWeak, interface_ptr: &DualModuleInterfacePtr, dual_module: &mut D) {
let mut tree_node_internal = tree_node_internal_ptr.write();
tree_node_internal.temporary_match = Some((MatchTarget::Peer(match_node_internal_ptr.downgrade()), tree_touching_ptr));
interface_ptr.set_grow_state(&tree_node_internal.origin.upgrade_force(), DualNodeGrowState::Stay, dual_module);
let tree_node = tree_node_internal.tree_node.as_ref().unwrap();
debug_assert!(tree_node.depth % 2 == 0, "only augment + node is possible");
for (child_ptr, _) in tree_node.children.iter() {
if child_ptr != &match_node_internal_ptr.downgrade() {
Self::match_subtree(child_ptr.upgrade_force(), interface_ptr, dual_module);
}
}
if tree_node.depth != 0 { let parent_node_internal_weak = tree_node.parent.as_ref().unwrap().0.clone();
let parent_node_internal_ptr = parent_node_internal_weak.upgrade_force();
let grandparent_node_internal_ptr = { let mut parent_node_internal = parent_node_internal_ptr.write();
let parent_tree_node = parent_node_internal.tree_node.as_ref().unwrap();
let grandparent_node_internal_weak = parent_tree_node.parent.as_ref().unwrap().0.clone();
parent_node_internal.temporary_match = Some((MatchTarget::Peer(grandparent_node_internal_weak.clone()), parent_tree_node.parent.as_ref().unwrap().1.clone()));
parent_node_internal.tree_node = None;
interface_ptr.set_grow_state(&parent_node_internal.origin.upgrade_force(), DualNodeGrowState::Stay, dual_module);
grandparent_node_internal_weak.upgrade_force()
};
let grandparent_touching_ptr = {
let grandparent_node_internal = grandparent_node_internal_ptr.read_recursive();
let grandparent_tree_node = grandparent_node_internal.tree_node.as_ref().unwrap();
let idx = grandparent_tree_node.children.iter().position(|(ptr, _)| ptr == &parent_node_internal_weak).expect("should find child");
grandparent_tree_node.children[idx].1.clone()
};
Self::augment_tree_given_matched(grandparent_node_internal_ptr, parent_node_internal_ptr, grandparent_touching_ptr, interface_ptr, dual_module);
}
tree_node_internal.tree_node = None;
}
pub fn augment_tree_given_virtual_vertex<D: DualModuleImpl>(&self, tree_node_internal_ptr: PrimalNodeInternalPtr, virtual_vertex_index: VertexIndex
, tree_touching_ptr: DualNodeWeak, interface_ptr: &DualModuleInterfacePtr, dual_module: &mut D) {
let mut tree_node_internal = tree_node_internal_ptr.write();
tree_node_internal.temporary_match = Some((MatchTarget::VirtualVertex(virtual_vertex_index), tree_touching_ptr));
interface_ptr.set_grow_state(&tree_node_internal.origin.upgrade_force(), DualNodeGrowState::Stay, dual_module);
let tree_node = tree_node_internal.tree_node.as_ref().unwrap();
debug_assert!(tree_node.depth % 2 == 0, "only augment + node is possible");
for (child_ptr, _) in tree_node.children.iter() {
Self::match_subtree(child_ptr.upgrade_force(), interface_ptr, dual_module);
}
if tree_node.depth != 0 { let parent_node_internal_weak = tree_node.parent.as_ref().unwrap().0.clone();
let parent_node_internal_ptr = parent_node_internal_weak.upgrade_force();
let grandparent_node_internal_ptr = { let mut parent_node_internal = parent_node_internal_ptr.write();
let parent_tree_node = parent_node_internal.tree_node.as_ref().unwrap();
let grandparent_node_internal_weak = parent_tree_node.parent.as_ref().unwrap().0.clone();
parent_node_internal.temporary_match = Some((MatchTarget::Peer(grandparent_node_internal_weak.clone()), parent_tree_node.parent.as_ref().unwrap().1.clone()));
parent_node_internal.tree_node = None;
interface_ptr.set_grow_state(&parent_node_internal.origin.upgrade_force(), DualNodeGrowState::Stay, dual_module);
grandparent_node_internal_weak.upgrade_force()
};
let grandparent_touching_ptr = {
let grandparent_node_internal = grandparent_node_internal_ptr.read_recursive();
let grandparent_tree_node = grandparent_node_internal.tree_node.as_ref().unwrap();
let idx = grandparent_tree_node.children.iter().position(|(ptr, _)| ptr == &parent_node_internal_weak).expect("should find child");
grandparent_tree_node.children[idx].1.clone()
};
Self::augment_tree_given_matched(grandparent_node_internal_ptr, parent_node_internal_ptr, grandparent_touching_ptr, interface_ptr, dual_module);
}
tree_node_internal.tree_node = None;
}
pub fn flatten_nodes(&self, flattened_nodes: &mut Vec<Option<PrimalNodeInternalPtr>>) {
let module = self.read_recursive();
let flattened_nodes_length = flattened_nodes.len();
if let Some(((left_child_weak, _), (right_child_weak, _))) = &module.children {
left_child_weak.upgrade_force().flatten_nodes(flattened_nodes);
right_child_weak.upgrade_force().flatten_nodes(flattened_nodes);
}
for node_index in 0..module.nodes_length {
let primal_node_internal_ptr = &module.nodes[node_index];
if let Some(primal_node_internal_ptr) = primal_node_internal_ptr {
primal_node_internal_ptr.update();
primal_node_internal_ptr.read_recursive().origin.upgrade_force().update();
}
flattened_nodes.push(primal_node_internal_ptr.clone());
}
debug_assert_eq!(flattened_nodes.len() - flattened_nodes_length, module.nodes_count() as usize);
}
pub fn slow_fuse(&self, left: &Self, right: &Self) {
let mut module = self.write();
module.is_fusion = true; for other in [left, right] {
let mut other_module = other.write();
other_module.is_fusion = true; let bias = module.nodes_length as NodeIndex;
for other_node_index in 0..other_module.nodes_length as NodeIndex {
let node_ptr = &other_module.nodes[other_node_index as usize];
if let Some(node_ptr) = node_ptr {
let mut node = node_ptr.write();
debug_assert_eq!(node.index, other_node_index);
node.index += bias;
}
module.nodes_length += 1;
if module.nodes.len() < module.nodes_length {
module.nodes.push(None);
}
module.nodes[(bias + other_node_index) as usize] = node_ptr.clone();
}
for node_index in other_module.possible_break.iter() {
module.possible_break.push(*node_index + bias);
}
}
}
pub fn fuse(&self, left: &Self, right: &Self) {
let parent_weak = self.downgrade();
let left_weak = left.downgrade();
let right_weak = right.downgrade();
let mut module = self.write();
module.is_fusion = true; debug_assert_eq!(module.nodes_length, 0, "fast fuse doesn't support non-empty fuse");
debug_assert!(module.children.is_none(), "cannot fuse twice");
let mut left_module = left.write();
let mut right_module = right.write();
debug_assert!(left_module.parent.is_none(), "cannot fuse an module twice");
debug_assert!(right_module.parent.is_none(), "cannot fuse an module twice");
left_module.parent = Some(parent_weak.clone());
right_module.parent = Some(parent_weak);
left_module.index_bias = 0;
right_module.index_bias = left_module.nodes_count();
module.children = Some((
(left_weak, left_module.nodes_count()),
(right_weak, right_module.nodes_count())
));
for other_module in [left_module, right_module] {
for node_index in other_module.possible_break.iter() {
module.possible_break.push(*node_index + other_module.index_bias);
}
}
}
#[allow(clippy::collapsible_else_if)]
pub fn sanity_check(&self) -> Result<Vec<Option<PrimalNodeInternalPtr>>, String> {
let mut flattened_nodes = vec![];
self.flatten_nodes(&mut flattened_nodes);
for (index, primal_module_internal_ptr) in flattened_nodes.iter().enumerate() {
if let Some(primal_module_internal_ptr) = primal_module_internal_ptr {
let primal_module_internal = primal_module_internal_ptr.read_recursive();
if primal_module_internal.index != index as NodeIndex { return Err(format!("primal node index wrong: expected {}, actual {}", index, primal_module_internal.index)) }
let origin_ptr = primal_module_internal.origin.upgrade_force();
let origin_node = origin_ptr.read_recursive();
if origin_node.index != primal_module_internal.index { return Err(format!("origin index wrong: expected {}, actual {}", index, origin_node.index)) }
if primal_module_internal.temporary_match.is_some() && primal_module_internal.tree_node.is_some() {
return Err(format!("{} temporary match and tree node cannot both exists", index))
}
if origin_node.parent_blossom.is_some() {
if primal_module_internal.tree_node.is_some() { return Err(format!("blossom internal node {index} is still in a tree")) }
if primal_module_internal.temporary_match.is_some() { return Err(format!("blossom internal node {index} is still matched")) }
}
if let Some((match_target, _)) = primal_module_internal.temporary_match.as_ref() {
if origin_node.grow_state != DualNodeGrowState::Stay { return Err(format!("matched node {index} is not set to Stay")) }
match match_target {
MatchTarget::Peer(peer_weak) => {
let peer_ptr = peer_weak.upgrade_force();
let peer = peer_ptr.read_recursive();
if let Some((peer_match_target, _)) = peer.temporary_match.as_ref() {
if peer_match_target != &MatchTarget::Peer(primal_module_internal_ptr.downgrade()) {
return Err(format!("match peer {} is not matched with {}, instead it's {:?}", peer.index, index, peer_match_target))
}
} else {
return Err("match peer is not marked as matched".to_string())
}
},
MatchTarget::VirtualVertex(_vertex_idx) => { }, }
}
if let Some(tree_node) = primal_module_internal.tree_node.as_ref() {
for (child_weak, _) in tree_node.children.iter() {
let child_ptr = child_weak.upgrade_force();
let child = child_ptr.read_recursive();
if let Some(child_tree_node) = child.tree_node.as_ref() {
if child_tree_node.parent.as_ref().map(|x| &x.0) != Some(&primal_module_internal_ptr.downgrade()) {
return Err(format!("{}'s child {} has a different parent, link broken", index, child.index))
}
} else { return Err(format!("{}'s child {} doesn't belong to any tree, link broken", index, child.index)) }
let module = self.read_recursive();
if child.index >= module.nodes_count() || module.get_node(child.index).is_none() {
return Err(format!("child's index {} is not in the interface", child.index))
}
let tracked_child_ptr = module.get_node(child.index).unwrap();
if tracked_child_ptr != child_ptr {
return Err(format!("the tracked ptr of child {} is not what's being pointed", child.index))
}
}
if let Some((parent_weak, _)) = tree_node.parent.as_ref() {
let parent_ptr = parent_weak.upgrade_force();
let parent = parent_ptr.read_recursive();
if let Some(parent_tree_node) = parent.tree_node.as_ref() {
let mut found_match_count = 0;
for (node_ptr, _) in parent_tree_node.children.iter() {
if node_ptr == &primal_module_internal_ptr.downgrade() {
found_match_count += 1;
}
}
if found_match_count != 1 {
return Err(format!("{} is the parent of {} but the child only presents {} times", parent.index, index, found_match_count))
}
} else { return Err(format!("{}'s parent {} doesn't belong to any tree, link broken", index, parent.index)) }
let module = self.read_recursive();
if parent.index >= module.nodes_count() || module.get_node(parent.index).is_none() {
return Err(format!("parent's index {} is not in the interface", parent.index))
}
let tracked_parent_ptr = module.get_node(parent.index).unwrap();
if tracked_parent_ptr != parent_ptr {
return Err(format!("the tracked ptr of child {} is not what's being pointed", parent.index))
}
} else {
if tree_node.root != primal_module_internal_ptr.downgrade() {
return Err(format!("{} is not the root of the tree, yet it has no parent", index))
}
}
let mut current_ptr = primal_module_internal_ptr.clone();
let mut current_up = 0;
loop {
let current = current_ptr.read_recursive();
let module = self.read_recursive();
if current.index >= module.nodes_count() || module.get_node(current.index).is_none() {
return Err(format!("current's index {} is not in the interface", current.index))
}
let tracked_current_ptr = module.get_node(current.index).unwrap();
if tracked_current_ptr != current_ptr {
return Err(format!("the tracked ptr of current {} is not what's being pointed", current.index))
}
if let Some(current_tree_node) = current.tree_node.as_ref() {
if let Some((current_parent_ptr, _)) = current_tree_node.parent.as_ref() {
let current_parent_ptr = current_parent_ptr.clone();
drop(current);
current_ptr = current_parent_ptr.upgrade_force();
current_up += 1;
} else {
if current_tree_node.root != current_ptr.downgrade() {
return Err(format!("current {} is not the root of the tree, yet it has no parent", current.index))
}
break
}
} else { return Err(format!("climbing up from {} to {} but it doesn't belong to a tree anymore", index, current.index)) }
}
if current_up != tree_node.depth {
return Err(format!("{} is marked with depth {} but the real depth is {}", index, tree_node.depth, current_up))
}
if current_ptr.downgrade() != tree_node.root {
return Err(format!("{} is marked with root {:?} but the real root is {:?}", index, tree_node.root, current_ptr))
}
}
}
}
Ok(flattened_nodes)
}
}
#[cfg(test)]
pub mod tests {
use super::*;
use super::super::example_codes::*;
use super::super::dual_module_serial::*;
use super::super::*;
pub fn primal_module_serial_basic_standard_syndrome_optional_viz(d: VertexNum, visualize_filename: Option<String>, defect_vertices: Vec<VertexIndex>, final_dual: Weight)
-> (DualModuleInterfacePtr, PrimalModuleSerialPtr, DualModuleSerial) {
println!("{defect_vertices:?}");
let half_weight = 500;
let mut code = CodeCapacityPlanarCode::new(d, 0.1, half_weight);
let mut visualizer = match visualize_filename.as_ref() {
Some(visualize_filename) => {
let visualizer = Visualizer::new(Some(visualize_data_folder() + visualize_filename.as_str()), code.get_positions(), true).unwrap();
print_visualize_link(visualize_filename.clone());
Some(visualizer)
}, None => None
};
let initializer = code.get_initializer();
let mut dual_module = DualModuleSerial::new_empty(&initializer);
let mut primal_module = PrimalModuleSerialPtr::new_empty(&initializer);
primal_module.write().debug_resolve_only_one = true; code.set_defect_vertices(&defect_vertices);
let interface_ptr = DualModuleInterfacePtr::new_empty();
primal_module.solve_visualizer(&interface_ptr, &code.get_syndrome(), &mut dual_module, visualizer.as_mut());
let perfect_matching = primal_module.perfect_matching(&interface_ptr, &mut dual_module);
let mut subgraph_builder = SubGraphBuilder::new(&initializer);
subgraph_builder.load_perfect_matching(&perfect_matching);
let subgraph = subgraph_builder.get_subgraph();
if let Some(visualizer) = visualizer.as_mut() {
visualizer.snapshot_combined("perfect matching and subgraph".to_string(), vec![&interface_ptr, &dual_module
, &perfect_matching, &VisualizeSubgraph::new(&subgraph)]).unwrap();
}
assert_eq!(interface_ptr.sum_dual_variables(), subgraph_builder.total_weight(), "unmatched sum dual variables");
assert_eq!(interface_ptr.sum_dual_variables(), final_dual * 2 * half_weight, "unexpected final dual variable sum");
(interface_ptr, primal_module, dual_module)
}
pub fn primal_module_serial_basic_standard_syndrome(d: VertexNum, visualize_filename: String, defect_vertices: Vec<VertexIndex>, final_dual: Weight)
-> (DualModuleInterfacePtr, PrimalModuleSerialPtr, DualModuleSerial) {
primal_module_serial_basic_standard_syndrome_optional_viz(d, Some(visualize_filename), defect_vertices, final_dual)
}
#[test]
fn primal_module_serial_basic_1() { let visualize_filename = format!("primal_module_serial_basic_1.json");
let defect_vertices = vec![18, 26, 34];
primal_module_serial_basic_standard_syndrome(7, visualize_filename, defect_vertices, 4);
}
#[test]
fn primal_module_serial_basic_2() { let visualize_filename = format!("primal_module_serial_basic_2.json");
let defect_vertices = vec![16];
primal_module_serial_basic_standard_syndrome(7, visualize_filename, defect_vertices, 1);
}
#[test]
fn primal_module_serial_basic_3() { let visualize_filename = format!("primal_module_serial_basic_3.json");
let defect_vertices = vec![16, 26];
primal_module_serial_basic_standard_syndrome(7, visualize_filename, defect_vertices, 3);
}
#[test]
fn primal_module_serial_basic_4() { let visualize_filename = format!("primal_module_serial_basic_4.json");
let defect_vertices = vec![16, 52, 65, 76, 112];
primal_module_serial_basic_standard_syndrome(11, visualize_filename, defect_vertices, 10);
}
#[test]
fn primal_module_serial_basic_5() { let visualize_filename = format!("primal_module_serial_basic_5.json");
let defect_vertices = vec![39, 51, 61, 62, 63, 64, 65, 75, 87, 67];
primal_module_serial_basic_standard_syndrome(11, visualize_filename, defect_vertices, 6);
}
#[test]
fn primal_module_serial_basic_6() { let visualize_filename = format!("primal_module_serial_basic_6.json");
let defect_vertices = vec![39, 51, 61, 62, 63, 64, 65, 75, 87];
primal_module_serial_basic_standard_syndrome(11, visualize_filename, defect_vertices, 6);
}
#[test]
fn primal_module_serial_basic_7() { let visualize_filename = format!("primal_module_serial_basic_7.json");
let defect_vertices = vec![37, 61, 63, 66, 68, 44];
primal_module_serial_basic_standard_syndrome(11, visualize_filename, defect_vertices, 7);
}
#[test]
fn primal_module_serial_basic_8() { let visualize_filename = format!("primal_module_serial_basic_8.json");
let defect_vertices = vec![61, 64, 67];
primal_module_serial_basic_standard_syndrome(11, visualize_filename, defect_vertices, 5);
}
#[test]
fn primal_module_serial_basic_9() { let visualize_filename = format!("primal_module_serial_basic_9.json");
let defect_vertices = vec![60, 63, 66, 30];
primal_module_serial_basic_standard_syndrome(11, visualize_filename, defect_vertices, 6);
}
#[test]
fn primal_module_serial_basic_10() { let visualize_filename = format!("primal_module_serial_basic_10.json");
let defect_vertices = vec![39, 52, 63, 90, 100];
primal_module_serial_basic_standard_syndrome(11, visualize_filename, defect_vertices, 9);
}
#[test]
fn primal_module_serial_basic_11() { let visualize_filename = format!("primal_module_serial_basic_11.json");
let defect_vertices = vec![13, 29, 52, 53, 58, 60, 71, 74, 76, 87, 96, 107, 112, 118, 121, 122, 134, 137, 141, 145, 152, 153, 154, 156, 157, 169, 186, 202, 203, 204, 230, 231];
primal_module_serial_basic_standard_syndrome(15, visualize_filename, defect_vertices, 20);
}
#[test]
fn primal_module_debug_1() { let visualize_filename = format!("primal_module_debug_1.json");
let defect_vertices = vec![34, 35, 84, 89, 92, 100, 141, 145, 149, 164, 193, 201, 205, 220, 235, 242, 243, 260, 261, 290, 300, 308, 309, 315, 317];
let max_half_weight = 500;
let mut code = CircuitLevelPlanarCode::new(7, 7, 0.01, max_half_weight);
let mut visualizer = Visualizer::new(Some(visualize_data_folder() + visualize_filename.as_str()), code.get_positions(), true).unwrap();
print_visualize_link(visualize_filename.clone());
let initializer = code.get_initializer();
let blossom_mwpm_result = blossom_v_mwpm(&initializer, &defect_vertices);
println!("blossom_mwpm_result: {blossom_mwpm_result:?}");
let blossom_details = detailed_matching(&initializer, &defect_vertices, &blossom_mwpm_result);
let mut blossom_total_weight = 0;
for detail in blossom_details.iter() {
println!(" {detail:?}");
blossom_total_weight += detail.weight;
}
let mut dual_module = DualModuleSerial::new_empty(&initializer);
let mut primal_module = PrimalModuleSerialPtr::new_empty(&initializer);
primal_module.write().debug_resolve_only_one = true; code.set_defect_vertices(&defect_vertices);
let interface_ptr = DualModuleInterfacePtr::new_empty();
primal_module.solve_visualizer(&interface_ptr, &code.get_syndrome(), &mut dual_module, Some(&mut visualizer));
let fusion_mwpm = primal_module.perfect_matching(&interface_ptr, &mut dual_module);
let fusion_mwpm_result = fusion_mwpm.legacy_get_mwpm_result(defect_vertices.clone());
let fusion_details = detailed_matching(&initializer, &defect_vertices, &fusion_mwpm_result);
let mut fusion_total_weight = 0;
for detail in fusion_details.iter() {
println!(" {detail:?}");
fusion_total_weight += detail.weight;
}
assert_eq!(fusion_total_weight, blossom_total_weight, "unexpected final dual variable sum");
{ let mut subgraph_builder = SubGraphBuilder::new(&initializer);
subgraph_builder.load_perfect_matching(&fusion_mwpm);
assert_eq!(subgraph_builder.total_weight(), blossom_total_weight, "unexpected final dual variable sum");
}
assert_eq!(interface_ptr.sum_dual_variables(), blossom_total_weight, "unexpected final dual variable sum");
}
#[test]
fn primal_module_debug_2() { let visualize_filename = format!("primal_module_debug_2.json");
let defect_vertices = vec![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, 138, 139, 140, 141, 150, 151, 153, 154, 155, 166, 171, 172, 181, 183, 184, 188, 200, 204, 219, 233];
let max_half_weight = 500;
let mut code = CodeCapacityPlanarCode::new(15, 0.3, max_half_weight);
let mut visualizer = Visualizer::new(Some(visualize_data_folder() + visualize_filename.as_str()), code.get_positions(), true).unwrap();
print_visualize_link(visualize_filename.clone());
let initializer = code.get_initializer();
let blossom_mwpm_result = blossom_v_mwpm(&initializer, &defect_vertices);
let blossom_details = detailed_matching(&initializer, &defect_vertices, &blossom_mwpm_result);
let mut blossom_total_weight = 0;
for detail in blossom_details.iter() {
println!(" {detail:?}");
blossom_total_weight += detail.weight;
}
let mut dual_module = DualModuleSerial::new_empty(&initializer);
let mut primal_module = PrimalModuleSerialPtr::new_empty(&initializer);
primal_module.write().debug_resolve_only_one = true; code.set_defect_vertices(&defect_vertices);
let interface_ptr = DualModuleInterfacePtr::new_empty();
primal_module.solve_visualizer(&interface_ptr, &code.get_syndrome(), &mut dual_module, Some(&mut visualizer));
let fusion_mwpm = primal_module.perfect_matching(&interface_ptr, &mut dual_module);
let fusion_mwpm_result = fusion_mwpm.legacy_get_mwpm_result(defect_vertices.clone());
let fusion_details = detailed_matching(&initializer, &defect_vertices, &fusion_mwpm_result);
let mut fusion_total_weight = 0;
for detail in fusion_details.iter() {
println!(" {detail:?}");
fusion_total_weight += detail.weight;
}
assert_eq!(fusion_total_weight, blossom_total_weight, "unexpected final dual variable sum");
{ let mut subgraph_builder = SubGraphBuilder::new(&initializer);
subgraph_builder.load_perfect_matching(&fusion_mwpm);
assert_eq!(subgraph_builder.total_weight(), blossom_total_weight, "unexpected final dual variable sum");
}
assert_eq!(interface_ptr.sum_dual_variables(), blossom_total_weight, "unexpected final dual variable sum");
}
#[test]
fn primal_module_debug_3() { let visualize_filename = format!("primal_module_debug_3.json");
let defect_vertices = vec![17, 34, 36, 54, 55, 74, 95, 96, 112, 113, 114, 115, 116, 130, 131, 132, 134, 150, 151, 154, 156, 171, 172, 173, 190];
let max_half_weight = 500;
let mut code = CodeCapacityPlanarCode::new(19, 0.499, max_half_weight);
let mut visualizer = Visualizer::new(Some(visualize_data_folder() + visualize_filename.as_str()), code.get_positions(), true).unwrap();
print_visualize_link(visualize_filename.clone());
let initializer = code.get_initializer();
let blossom_mwpm_result = blossom_v_mwpm(&initializer, &defect_vertices);
let blossom_details = detailed_matching(&initializer, &defect_vertices, &blossom_mwpm_result);
let mut blossom_total_weight = 0;
for detail in blossom_details.iter() {
println!(" {detail:?}");
blossom_total_weight += detail.weight;
}
let mut dual_module = DualModuleSerial::new_empty(&initializer);
let mut primal_module = PrimalModuleSerialPtr::new_empty(&initializer);
primal_module.write().debug_resolve_only_one = true; code.set_defect_vertices(&defect_vertices);
let interface_ptr = DualModuleInterfacePtr::new_empty();
primal_module.solve_visualizer(&interface_ptr, &code.get_syndrome(), &mut dual_module, Some(&mut visualizer));
let fusion_mwpm = primal_module.perfect_matching(&interface_ptr, &mut dual_module);
let fusion_mwpm_result = fusion_mwpm.legacy_get_mwpm_result(defect_vertices.clone());
let fusion_details = detailed_matching(&initializer, &defect_vertices, &fusion_mwpm_result);
let mut fusion_total_weight = 0;
for detail in fusion_details.iter() {
println!(" {detail:?}");
fusion_total_weight += detail.weight;
}
assert_eq!(fusion_total_weight, blossom_total_weight, "unexpected final dual variable sum");
{ let mut subgraph_builder = SubGraphBuilder::new(&initializer);
subgraph_builder.load_perfect_matching(&fusion_mwpm);
assert_eq!(subgraph_builder.total_weight(), blossom_total_weight, "unexpected final dual variable sum");
}
assert_eq!(interface_ptr.sum_dual_variables(), blossom_total_weight, "unexpected final dual variable sum");
}
#[test]
fn primal_module_debug_4() { let visualize_filename = format!("primal_module_debug_4.json");
let defect_vertices = vec![1, 3, 6, 8, 9, 11, 13];
let max_half_weight = 500;
let mut code = CodeCapacityRepetitionCode::new(15, 0.499, max_half_weight);
let mut visualizer = Visualizer::new(Some(visualize_data_folder() + visualize_filename.as_str()), code.get_positions(), true).unwrap();
print_visualize_link(visualize_filename.clone());
let initializer = code.get_initializer();
let blossom_mwpm_result = blossom_v_mwpm(&initializer, &defect_vertices);
let blossom_details = detailed_matching(&initializer, &defect_vertices, &blossom_mwpm_result);
let mut blossom_total_weight = 0;
for detail in blossom_details.iter() {
println!(" {detail:?}");
blossom_total_weight += detail.weight;
}
let mut dual_module = DualModuleSerial::new_empty(&initializer);
let mut primal_module = PrimalModuleSerialPtr::new_empty(&initializer);
primal_module.write().debug_resolve_only_one = true; code.set_defect_vertices(&defect_vertices);
let interface_ptr = DualModuleInterfacePtr::new_empty();
primal_module.solve_visualizer(&interface_ptr, &code.get_syndrome(), &mut dual_module, Some(&mut visualizer));
let fusion_mwpm = primal_module.perfect_matching(&interface_ptr, &mut dual_module);
let fusion_mwpm_result = fusion_mwpm.legacy_get_mwpm_result(defect_vertices.clone());
let fusion_details = detailed_matching(&initializer, &defect_vertices, &fusion_mwpm_result);
let mut fusion_total_weight = 0;
for detail in fusion_details.iter() {
println!(" {detail:?}");
fusion_total_weight += detail.weight;
}
assert_eq!(fusion_total_weight, blossom_total_weight, "unexpected final dual variable sum");
{ let mut subgraph_builder = SubGraphBuilder::new(&initializer);
subgraph_builder.load_perfect_matching(&fusion_mwpm);
assert_eq!(subgraph_builder.total_weight(), blossom_total_weight, "unexpected final dual variable sum");
}
assert_eq!(interface_ptr.sum_dual_variables(), blossom_total_weight, "unexpected final dual variable sum");
}
#[test]
fn primal_module_debug_5() { let visualize_filename = format!("primal_module_debug_5.json");
let defect_vertices = vec![0, 1, 3, 8, 9];
let max_half_weight = 500;
let mut code = CodeCapacityRepetitionCode::new(11, 0.03, max_half_weight);
let mut visualizer = Visualizer::new(Some(visualize_data_folder() + visualize_filename.as_str()), code.get_positions(), true).unwrap();
print_visualize_link(visualize_filename.clone());
let initializer = code.get_initializer();
let blossom_mwpm_result = blossom_v_mwpm(&initializer, &defect_vertices);
let blossom_details = detailed_matching(&initializer, &defect_vertices, &blossom_mwpm_result);
let mut blossom_total_weight = 0;
for detail in blossom_details.iter() {
println!(" {detail:?}");
blossom_total_weight += detail.weight;
}
let mut dual_module = DualModuleSerial::new_empty(&initializer);
let mut primal_module = PrimalModuleSerialPtr::new_empty(&initializer);
code.set_defect_vertices(&defect_vertices);
let interface_ptr = DualModuleInterfacePtr::new_empty();
primal_module.solve_visualizer(&interface_ptr, &code.get_syndrome(), &mut dual_module, Some(&mut visualizer));
let fusion_mwpm = primal_module.perfect_matching(&interface_ptr, &mut dual_module);
let fusion_mwpm_result = fusion_mwpm.legacy_get_mwpm_result(defect_vertices.clone());
let fusion_details = detailed_matching(&initializer, &defect_vertices, &fusion_mwpm_result);
let mut fusion_total_weight = 0;
for detail in fusion_details.iter() {
println!(" {detail:?}");
fusion_total_weight += detail.weight;
}
assert_eq!(fusion_total_weight, blossom_total_weight, "unexpected final dual variable sum");
{ let mut subgraph_builder = SubGraphBuilder::new(&initializer);
subgraph_builder.load_perfect_matching(&fusion_mwpm);
assert_eq!(subgraph_builder.total_weight(), blossom_total_weight, "unexpected final dual variable sum");
}
assert_eq!(interface_ptr.sum_dual_variables(), blossom_total_weight, "unexpected final dual variable sum");
}
#[test]
fn primal_module_serial_perfect_matching_1() { let defect_vertices = vec![39, 51, 61, 62, 63, 64, 65, 75, 87, 67];
let (interface_ptr, mut primal_module, mut dual_module) = primal_module_serial_basic_standard_syndrome_optional_viz(11, None, defect_vertices, 6);
let intermediate_matching = primal_module.intermediate_matching(&interface_ptr, &mut dual_module);
println!("intermediate_matching: {intermediate_matching:?}");
let perfect_matching = primal_module.perfect_matching(&interface_ptr, &mut dual_module);
println!("perfect_matching: {perfect_matching:?}");
}
#[test]
fn primal_module_debug_6() { let visualize_filename = format!("primal_module_debug_6.json");
let defect_vertices = vec![13, 34, 87, 107, 276, 296];
let erasures = vec![13, 33, 174, 516];
let max_half_weight = 500;
let mut code = CodeCapacityPlanarCode::new(19, 0., max_half_weight);
code.set_erasure_probability(0.003);
let mut visualizer = Visualizer::new(Some(visualize_data_folder() + visualize_filename.as_str()), code.get_positions(), true).unwrap();
print_visualize_link(visualize_filename.clone());
let mut initializer = code.get_initializer();
for edge_index in erasures.iter() {
let (vertex_idx_1, vertex_idx_2, _) = &initializer.weighted_edges[*edge_index];
initializer.weighted_edges[*edge_index] = (*vertex_idx_1, *vertex_idx_2, 0);
}
let blossom_mwpm_result = blossom_v_mwpm(&initializer, &defect_vertices);
let blossom_details = detailed_matching(&initializer, &defect_vertices, &blossom_mwpm_result);
let mut blossom_total_weight = 0;
for detail in blossom_details.iter() {
println!(" {detail:?}");
blossom_total_weight += detail.weight;
}
let mut dual_module = DualModuleSerial::new_empty(&initializer);
let mut primal_module = PrimalModuleSerialPtr::new_empty(&initializer);
code.set_defect_vertices(&defect_vertices);
let interface_ptr = DualModuleInterfacePtr::new_empty();
primal_module.solve_visualizer(&interface_ptr, &code.get_syndrome(), &mut dual_module, Some(&mut visualizer));
let fusion_mwpm = primal_module.perfect_matching(&interface_ptr, &mut dual_module);
let fusion_mwpm_result = fusion_mwpm.legacy_get_mwpm_result(defect_vertices.clone());
let fusion_details = detailed_matching(&initializer, &defect_vertices, &fusion_mwpm_result);
let mut fusion_total_weight = 0;
for detail in fusion_details.iter() {
println!(" {detail:?}");
fusion_total_weight += detail.weight;
}
assert_eq!(fusion_total_weight, blossom_total_weight, "unexpected final dual variable sum");
{ let mut subgraph_builder = SubGraphBuilder::new(&initializer);
subgraph_builder.load_perfect_matching(&fusion_mwpm);
assert_eq!(subgraph_builder.total_weight(), blossom_total_weight, "unexpected final dual variable sum");
}
assert_eq!(interface_ptr.sum_dual_variables(), blossom_total_weight, "unexpected final dual variable sum");
}
}