use std::collections::BTreeMap;
use anyhow::Result;
use fixedbitset::FixedBitSet;
use crate::algorithms::equal_angle::normalize_cycle_1based;
use crate::splits::asplit::ASplit;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum Compatibility {
#[default]
Unknown,
Compatible,
Cyclic,
WeaklyCompatible,
Incompatible,
}
#[derive(Debug, Clone, Default)]
pub struct SplitsFormat {
pub labels: bool,
pub weights: bool,
pub confidences: bool,
pub intervals: bool,
pub show_both_sides: bool,
}
#[derive(Debug, Clone)]
pub struct SplitsBlock {
pub splits: Vec<ASplit>, compatibility: Compatibility,
fit: f32,
threshold: f32,
cycle: Option<Vec<usize>>, split_labels: BTreeMap<usize, String>,
format: SplitsFormat,
}
impl SplitsBlock {
pub fn new() -> Self {
Self {
splits: Vec::new(),
compatibility: Compatibility::Unknown,
fit: -1.0,
threshold: 0.0,
cycle: None,
split_labels: BTreeMap::new(),
format: SplitsFormat {
labels: false,
weights: true,
confidences: false,
intervals: false,
show_both_sides: false,
},
}
}
pub fn clear(&mut self) {
self.splits.clear();
self.compatibility = Compatibility::Unknown;
self.fit = -1.0;
self.threshold = 0.0;
self.cycle = None;
self.split_labels.clear();
self.format = SplitsFormat::default();
}
pub fn set_splits(&mut self, splits: Vec<ASplit>) {
self.splits = splits;
}
pub fn nsplits(&self) -> usize {
self.splits.len()
}
pub fn splits(&self) -> impl Iterator<Item = &ASplit> {
self.splits.iter()
}
pub fn get_splits(&self) -> &[ASplit] {
&self.splits
}
pub fn get(&self, i: usize) -> &ASplit {
&self.splits[i - 1]
}
pub fn push(&mut self, s: ASplit) -> usize {
self.splits.push(s);
self.splits.len()
}
pub fn set_compatibility(&mut self, c: Compatibility) {
self.compatibility = c;
}
pub fn compatibility(&self) -> Compatibility {
self.compatibility
}
pub fn set_fit(&mut self, fit: f32) {
self.fit = fit;
}
pub fn fit(&self) -> f32 {
self.fit
}
pub fn set_threshold(&mut self, thr: f32) {
self.threshold = thr;
}
pub fn threshold(&self) -> f32 {
self.threshold
}
pub fn format(&self) -> &SplitsFormat {
&self.format
}
pub fn format_mut(&mut self) -> &mut SplitsFormat {
&mut self.format
}
pub fn split_labels(&self) -> &BTreeMap<usize, String> {
&self.split_labels
}
pub fn split_labels_mut(&mut self) -> &mut BTreeMap<usize, String> {
&mut self.split_labels
}
pub fn set_split_label<S: Into<String>>(&mut self, sid: usize, label: S) {
self.split_labels.insert(sid, label.into());
}
pub fn cycle(&self) -> Option<&[usize]> {
self.cycle.as_deref()
}
pub fn set_cycle(&mut self, mut cycle: Vec<usize>, normalize: bool) -> Result<()> {
if normalize {
cycle = normalize_cycle_1based(&cycle)?;
}
let mut seen = FixedBitSet::with_capacity(cycle.len() + 1);
for &v in &cycle {
if v >= seen.len() {
seen.grow(v + 1);
}
if seen.contains(v) {
self.cycle = None;
return Err(anyhow::anyhow!("cycle is not a permutation"));
}
seen.insert(v);
}
self.cycle = Some(cycle);
Ok(())
}
pub fn has_confidence_values(&self) -> bool {
self.splits.iter().any(|s| s.confidence != -1.0)
}
}
impl Default for SplitsBlock {
fn default() -> Self {
Self::new()
}
}
pub trait SplitsProvider {
fn nsplits(&self) -> usize;
fn split(&self, id: usize) -> &ASplit;
fn cycle(&self) -> Option<&[usize]>;
}
impl SplitsProvider for SplitsBlock {
fn nsplits(&self) -> usize {
self.nsplits()
}
fn split(&self, id: usize) -> &ASplit {
self.get(id)
}
fn cycle(&self) -> Option<&[usize]> {
self.cycle()
}
}