use core::fmt;
use std::fmt::{Display, Write};
use itertools::Itertools;
use itertools::Position::{First, Last, Middle, Only};
use ndarray::Array1;
use crate::linalg::affine::{AffFunc, Polytope};
use crate::linalg::impl_affineformat::{FormatOptions, write_func, write_poly};
use crate::tree::graph::TreeNode;
#[derive(Clone, Debug)]
pub enum NodeState {
Indeterminate,
Infeasible,
Feasible,
FeasibleWitness(Vec<Array1<f64>>),
}
impl NodeState {
#[inline(always)]
pub fn is_feasible(&self) -> bool {
matches!(self, NodeState::Feasible | NodeState::FeasibleWitness(_))
}
#[inline(always)]
pub fn is_infeasible(&self) -> bool {
matches!(self, NodeState::Infeasible)
}
#[inline(always)]
pub fn is_indetermined(&self) -> bool {
matches!(self, NodeState::Indeterminate)
}
}
#[derive(Clone, Debug)]
pub struct AffContent {
pub aff: AffFunc,
pub state: NodeState,
}
impl AffContent {
pub fn new(aff: AffFunc) -> AffContent {
AffContent {
aff,
state: NodeState::Indeterminate,
}
}
pub fn to_poly(&self) -> Polytope {
Polytope::from_mats(self.aff.mat.clone(), self.aff.bias.clone())
}
pub fn feasible_witnesses(&self) -> Vec<Array1<f64>> {
match &self.state {
NodeState::FeasibleWitness(witnesses) => witnesses.clone(),
_ => Vec::new(),
}
}
}
pub type AffNode<const K: usize> = TreeNode<AffContent, K>;
impl<const K: usize> Display for AffNode<K> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.isleaf {
write_terminal(f, &self.value.aff, true)
} else {
write_predicate(f, &self.value.aff, true)
}
}
}
pub fn write_predicate(
f: &mut fmt::Formatter,
pred: &AffFunc,
_pretty_print: bool,
) -> std::fmt::Result {
let opt = FormatOptions::default_poly();
write_poly(
f,
Polytope::from_mats(pred.mat.clone(), pred.bias.clone()).view(),
&opt,
)
}
pub fn write_terminal(
f: &mut fmt::Formatter,
pred: &AffFunc,
_pretty_print: bool,
) -> std::fmt::Result {
let opt = FormatOptions::default_func();
write_func(f, pred.view(), &opt)
}
pub fn write_children<T, F: Write, const K: usize>(
f: &mut F,
node: &TreeNode<T, K>,
) -> std::fmt::Result {
for (pos, (label, idx)) in node.children_iter().with_position() {
match pos {
First | Middle => write!(f, "{}->{}, ", label, idx)?,
Only | Last => write!(f, "{}->{}", label, idx)?,
}
}
Ok(())
}