use super::*;
use crate::solver::chordal::*;
pub(crate) struct ParentChildMergeStrategy {
stop: bool,
clique_index: usize,
t_fill: usize,
t_size: usize,
}
impl ParentChildMergeStrategy {
pub(crate) fn new() -> Self {
let t_fill = 8; let t_size = 8;
Self {
stop: false,
clique_index: 0,
t_fill,
t_size,
}
}
}
impl MergeStrategy for ParentChildMergeStrategy {
fn initialise(&mut self, t: &mut SuperNodeTree) {
self.clique_index = t.snode.len() - 2;
}
fn is_done(&self) -> bool {
self.stop
}
fn traverse(&mut self, t: &SuperNodeTree) -> Option<(usize, usize)> {
let c = t.snode_post[self.clique_index];
Some((t.snode_parent[c], c))
}
fn evaluate(&mut self, t: &SuperNodeTree, cand: (usize, usize)) -> bool {
if self.stop {
return false;
}
let (parent, child) = cand;
let (dim_parent_snode, dim_parent_sep) = clique_dim(t, parent);
let (dim_clique_snode, dim_clique_sep) = clique_dim(t, child);
let fill = fill_in(
dim_clique_snode,
dim_clique_sep,
dim_parent_snode,
dim_parent_sep,
);
let max_snode = std::cmp::max(dim_clique_snode, dim_parent_snode);
fill <= self.t_fill || max_snode <= self.t_size
}
fn merge_two_cliques(&self, t: &mut SuperNodeTree, cand: (usize, usize)) {
let (p, ch) = determine_parent(t, cand.0, cand.1);
set_union_into_indexed(&mut t.snode, p, ch);
t.snode[ch].clear();
t.separators[ch].clear();
for &grandch in t.snode_children[ch].iter() {
t.snode_parent[grandch] = p;
}
t.snode_parent[ch] = INACTIVE_NODE;
t.snode_children[p].shift_remove(&ch); set_union_into_indexed(&mut t.snode_children, p, ch);
t.snode_children[ch].clear();
t.n_cliques -= 1;
}
fn update_strategy(&mut self, _t: &SuperNodeTree, _cand: (usize, usize), _do_merge: bool) {
if self.clique_index == 0 {
self.stop = true
}
else {
self.clique_index -= 1
}
}
fn post_process_merge(&mut self, t: &mut SuperNodeTree) {
post_order(
&mut t.snode_post,
&t.snode_parent,
&mut t.snode_children,
t.n_cliques,
);
}
}
fn determine_parent(t: &SuperNodeTree, c1: usize, c2: usize) -> (usize, usize) {
if t.snode_children[c1].contains(&c2) {
(c1, c2)
} else {
(c2, c1)
}
}
fn clique_dim(t: &SuperNodeTree, i: usize) -> (usize, usize) {
(t.snode[i].len(), t.separators[i].len())
}
fn fill_in(
dim_clique_snode: usize,
dim_clique_sep: usize,
dim_parent_snode: usize,
dim_parent_sep: usize,
) -> usize {
let dim_parent = dim_parent_snode + dim_parent_sep;
let dim_clique = dim_clique_snode + dim_clique_sep;
(dim_parent - dim_clique_sep) * (dim_clique - dim_clique_sep)
}