#[allow(unused_imports)]
use crate::mwpf::shim::prelude::*;
use std::collections::VecDeque;
use std::sync::Arc;
use crate::mwpf::dual_module::*;
use crate::mwpf::itertools::Itertools;
use crate::mwpf::ordered_float::OrderedFloat;
use crate::mwpf::primal_module_serial::ClusterAffinity;
use crate::mwpf::relaxer_optimizer::OptimizerResult;
use crate::mwpf::util::*;
use crate::mwpf::visualize::*;
use hashbrown::HashSet;
pub type Affinity = OrderedFloat;
const MAX_HISTORY: usize = 10;
pub trait PrimalModuleImpl {
fn new_empty(solver_initializer: &Arc<SolverInitializer>) -> Self;
fn clear(&mut self);
fn load<D: DualModuleImpl>(&mut self, interface_ptr: &DualModuleInterfacePtr, dual_module: &mut D);
fn resolve(
&mut self,
dual_report: DualReport,
interface: &DualModuleInterfacePtr,
dual_module: &mut impl DualModuleImpl,
) -> bool;
fn old_resolve(
&mut self,
_group_max_update_length: DualReport,
_interface: &DualModuleInterfacePtr,
_dual_module: &mut impl DualModuleImpl,
) -> bool {
false
}
fn resolve_tune(
&mut self,
_obstacles: FastIterSet<Obstacle>,
_interface: &DualModuleInterfacePtr,
_dual_module: &mut impl DualModuleImpl,
) -> (FastIterSet<Obstacle>, bool) {
panic!("`resolve_tune` not implemented, this primal module does not work with tuning mode");
}
fn solve(
&mut self,
interface: &DualModuleInterfacePtr,
syndrome_pattern: Arc<SyndromePattern>,
dual_module: &mut impl DualModuleImpl,
) {
interface.load(syndrome_pattern, dual_module);
self.load(interface, dual_module);
self.solve_step_callback_interface_loaded(interface, dual_module, |_, _, _, _| {})
}
fn visualizer_callback<D: DualModuleImpl + MWPSVisualizer>(
visualizer: &mut Visualizer,
) -> impl FnMut(&DualModuleInterfacePtr, &mut D, &mut Self, &DualReport)
where
Self: MWPSVisualizer + Sized,
{
|interface: &DualModuleInterfacePtr, dual_module: &mut D, primal_module: &mut Self, dual_report: &DualReport| {
if cfg!(debug_assertions) {
println!("dual_report: {:?}", dual_report);
}
if dual_report.is_unbounded() {
visualizer
.snapshot_combined("unbounded grow".to_string(), vec![interface, dual_module, primal_module])
.unwrap();
} else if let Some(length) = dual_report.get_valid_growth() {
visualizer
.snapshot_combined(format!("grow {length}"), vec![interface, dual_module, primal_module])
.unwrap();
} else {
let first_conflict = format!("{:?}", dual_report.peek().unwrap());
visualizer
.snapshot_combined(
format!("resolve {first_conflict}"),
vec![interface, dual_module, primal_module],
)
.unwrap();
};
}
}
fn weight_preprocessing<D: DualModuleImpl + MWPSVisualizer>(
&mut self,
syndrome_pattern: Arc<SyndromePattern>,
dual_module: &mut D,
initializer: &Arc<SolverInitializer>,
) -> Arc<SyndromePattern> {
if let Some((weights, mix_ratio, floor_weight)) = syndrome_pattern.override_weights.as_ref() {
let mut weights = weights.clone();
if let Some(floor_weight) = floor_weight {
weights.iter_mut().for_each(|w| {
if *w < *floor_weight {
*w = floor_weight.clone();
}
});
}
dual_module.update_weights(weights, mix_ratio.clone());
} else {
let mut weight_updates: FastIterMap<EdgeIndex, Weight> = FastIterMap::new();
for &herald_index in syndrome_pattern.heralds.iter() {
for (edge_index, weight) in initializer.heralds[herald_index].iter() {
let value = weight_updates.remove(edge_index);
let original_weight = value
.as_ref()
.unwrap_or_else(|| &initializer.weighted_edges[*edge_index].weight);
let mixed_weight = exclusive_weight_sum(original_weight, weight);
weight_updates.insert(*edge_index, mixed_weight);
}
}
for &edge_index in syndrome_pattern.erasures.iter() {
use crate::mwpf::num_traits::Zero;
weight_updates.insert(edge_index, Weight::zero());
}
dual_module.set_weights(weight_updates);
}
dual_module.adjust_weights_for_negative_edges();
let flip_vertices = dual_module.get_flip_vertices();
if flip_vertices.is_empty() {
return syndrome_pattern;
}
let mut moved_out_set = syndrome_pattern
.defect_vertices
.iter()
.cloned()
.collect::<HashSet<VertexIndex>>();
for to_flip in flip_vertices.iter() {
if moved_out_set.contains(to_flip) {
moved_out_set.remove(to_flip);
} else {
moved_out_set.insert(*to_flip);
}
}
Arc::new(SyndromePattern::new_vertices(moved_out_set.into_iter().collect()))
}
fn solve_visualizer<D: DualModuleImpl + MWPSVisualizer>(
&mut self,
interface: &DualModuleInterfacePtr,
syndrome_pattern: Arc<SyndromePattern>,
dual_module: &mut D,
visualizer: Option<&mut Visualizer>,
) where
Self: MWPSVisualizer + Sized,
{
if let Some(visualizer) = visualizer {
let callback = Self::visualizer_callback(visualizer);
interface.load(syndrome_pattern, dual_module);
self.load(interface, dual_module);
self.solve_step_callback_interface_loaded(interface, dual_module, callback);
visualizer
.snapshot_combined("solved".to_string(), vec![interface, dual_module, self])
.unwrap();
} else {
self.solve(interface, syndrome_pattern, dual_module);
}
}
fn solve_step_callback_interface_loaded<D: DualModuleImpl, F>(
&mut self,
interface: &DualModuleInterfacePtr,
dual_module: &mut D,
mut callback: F,
) where
F: FnMut(&DualModuleInterfacePtr, &mut D, &mut Self, &DualReport),
{
PYTHON_SIGNAL_CHECKER.skip_next();
let mut dual_report = dual_module.report();
while !dual_report.is_unbounded() {
PYTHON_SIGNAL_CHECKER.check().unwrap();
callback(interface, dual_module, self, &dual_report);
match dual_report.get_valid_growth() {
Some(length) => dual_module.grow(length),
None => {
self.resolve(dual_report, interface, dual_module);
}
}
dual_report = dual_module.report();
}
let mut start = true;
while self.has_more_plugins() {
PYTHON_SIGNAL_CHECKER.check().unwrap();
if start {
start = false;
dual_module.advance_mode();
}
self.update_sorted_clusters_aff(dual_module);
let cluster_affs = self.get_sorted_clusters_aff();
for cluster_affinity in cluster_affs.into_iter().sorted() {
let cluster_index = cluster_affinity.cluster_index;
let mut dual_node_deltas = FastIterMap::new();
let (mut resolved, optimizer_result) =
self.resolve_cluster_tune(cluster_index, interface, dual_module, &mut dual_node_deltas);
let mut obstacles = dual_module.get_obstacles_tune(optimizer_result, dual_node_deltas);
let mut order: VecDeque<FastIterSet<Obstacle>> = VecDeque::with_capacity(MAX_HISTORY); let mut current_sequences: Vec<(usize, FastIterSet<Obstacle>)> = Vec::new();
'_resolving: while !resolved {
PYTHON_SIGNAL_CHECKER.check().unwrap();
let (_obstacles, _resolved) = self.resolve_tune(obstacles.clone(), interface, dual_module);
let drained: Vec<(usize, FastIterSet<Obstacle>)> = std::mem::take(&mut current_sequences);
for (idx, start) in drained.into_iter() {
if _obstacles.eq(&start) {
dual_module.end_tuning();
break '_resolving;
}
let candidate_index = order.len() - idx - 1;
if let Some(candidate) = order.get(candidate_index) {
if _obstacles.eq(candidate) {
current_sequences.push((idx + 1, start));
}
} else {
eprintln!(
"Warning: candidate index {} out of bounds, order length {}, idx {}, start {:?}, candidate {:?}",
candidate_index,
order.len(),
idx,
start,
order.get(candidate_index)
);
}
}
order.push_back(_obstacles.clone());
if order.len() > MAX_HISTORY {
order.pop_front();
current_sequences = current_sequences
.into_iter()
.filter_map(|(x, start)| {
if x == 0 {
None
} else {
Some((x - 1, start))
}
})
.collect();
}
for (idx, c) in order.iter().enumerate() {
if c.eq(&_obstacles) {
current_sequences.push((idx, c.clone()));
}
}
if _resolved {
dual_module.end_tuning();
break;
}
obstacles = _obstacles;
resolved = _resolved;
}
}
}
}
fn subgraph(&mut self, interface: &DualModuleInterfacePtr, dual_module: &mut impl DualModuleImpl) -> OutputSubgraph;
fn subgraph_range(
&mut self,
interface: &DualModuleInterfacePtr,
dual_module: &mut impl DualModuleImpl,
) -> (OutputSubgraph, WeightRange) {
let output_subgraph = self.subgraph(interface, dual_module);
let weight_range = WeightRange::new(
interface.sum_dual_variables() + dual_module.get_negative_weight_sum(),
dual_module.get_subgraph_weight(&output_subgraph.subgraph) + dual_module.get_negative_weight_sum(),
);
(output_subgraph, weight_range)
}
fn generate_profiler_report(&self) -> serde_json::Value {
json!({})
}
fn has_more_plugins(&mut self) -> bool {
false
}
fn pending_clusters(&mut self) -> Vec<usize> {
panic!("not implemented `pending_clusters`");
}
fn resolve_cluster(
&mut self,
_cluster_index: NodeIndex,
_interface_ptr: &DualModuleInterfacePtr,
_dual_module: &mut impl DualModuleImpl,
) -> bool {
panic!("not implemented `resolve_cluster`");
}
fn resolve_cluster_tune(
&mut self,
_cluster_index: NodeIndex,
_interface_ptr: &DualModuleInterfacePtr,
_dual_module: &mut impl DualModuleImpl,
_dual_node_deltas: &mut FastIterMap<OrderedDualNodePtr, (Rational, NodeIndex)>,
) -> (bool, OptimizerResult) {
panic!("not implemented `resolve_cluster_tune`");
}
fn update_sorted_clusters_aff<D: DualModuleImpl>(&mut self, _dual_module: &mut D) {
panic!("not implemented `update_sorted_clusters_aff`");
}
fn get_sorted_clusters_aff(&mut self) -> FastIterSet<ClusterAffinity> {
panic!("not implemented `get_sorted_clusters_aff`");
}
}