use fixedbitset::FixedBitSet;
use crate::splits::bipartition::BiPartition;
use std::fmt::{self, Display};
use std::hash::{Hash, Hasher};
#[derive(Debug, Clone)]
pub struct ASplit {
pub base: BiPartition,
pub weight: f64,
pub confidence: f64,
pub label: Option<String>,
}
impl ASplit {
pub fn new(a: FixedBitSet, b: FixedBitSet) -> Self {
Self::new_full(a, b, 1.0, -1.0, None)
}
pub fn new_full(
a: FixedBitSet,
b: FixedBitSet,
weight: f64,
confidence: f64,
label: Option<String>,
) -> Self {
let base = BiPartition::new(a, b);
Self {
base,
weight,
confidence,
label,
}
}
pub fn from_a_ntax(a: FixedBitSet, ntax: usize) -> Self {
Self::from_a_ntax_full(a, ntax, 1.0, -1.0, None)
}
pub fn from_a_ntax_with_weight(a: FixedBitSet, ntax: usize, weight: f64) -> Self {
Self::from_a_ntax_full(a, ntax, weight, -1.0, None)
}
pub fn from_a_ntax_with_weight_conf(
a: FixedBitSet,
ntax: usize,
weight: f64,
confidence: f64,
) -> Self {
Self::from_a_ntax_full(a, ntax, weight, confidence, None)
}
pub fn from_a_ntax_full(
a: FixedBitSet,
ntax: usize,
weight: f64,
confidence: f64,
label: Option<String>,
) -> Self {
let b = complement_1_based(&a, ntax);
Self::new_full(a, b, weight, confidence, label)
}
pub fn label(&self) -> Option<&str> {
self.label.as_deref()
}
pub fn get_a(&self) -> &FixedBitSet {
self.base.get_a()
}
pub fn get_b(&self) -> &FixedBitSet {
self.base.get_b()
}
pub fn ntax(&self) -> usize {
self.base.ntax()
}
pub fn size(&self) -> usize {
self.base.size()
}
pub fn part_containing(&self, t: usize) -> &FixedBitSet {
self.base.part_containing(t)
}
pub fn part_not_containing(&self, t: usize) -> &FixedBitSet {
self.base.part_not_containing(t)
}
pub fn smaller_part(&self) -> &FixedBitSet {
self.base.smaller_part()
}
pub fn is_trivial(&self) -> bool {
self.base.is_trivial()
}
pub fn base(&self) -> &BiPartition {
&self.base
}
}
impl PartialEq for ASplit {
fn eq(&self, other: &Self) -> bool {
same_bits_1based(self.part_containing(1), other.part_containing(1))
&& same_bits_1based(self.part_not_containing(1), other.part_not_containing(1))
}
}
impl Eq for ASplit {}
impl Hash for ASplit {
fn hash<H: Hasher>(&self, state: &mut H) {
self.base.hash(state);
}
}
impl Display for ASplit {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{} weight={} confidence={} label={}",
self.base,
self.weight,
self.confidence,
self.label.as_deref().unwrap_or("null")
)
}
}
fn same_bits_1based(a: &FixedBitSet, b: &FixedBitSet) -> bool {
let mut seen = FixedBitSet::with_capacity(a.len().max(b.len()));
seen.union_with(a);
seen.union_with(b);
for i in seen.ones() {
if i == 0 {
continue;
}
let ai = a.contains(i);
let bi = b.contains(i);
if ai != bi {
return false;
}
}
true
}
fn complement_1_based(a: &FixedBitSet, ntax: usize) -> FixedBitSet {
let mut out = FixedBitSet::with_capacity(ntax + 1);
out.grow(ntax + 1);
for i in 1..=ntax {
if !a.contains(i) {
out.set(i, true);
}
}
out
}
pub trait ASplitView {
fn weight(&self) -> f64;
fn size(&self) -> usize;
fn smaller_part(&self) -> &fixedbitset::FixedBitSet;
fn ntax(&self) -> usize;
}
impl ASplitView for ASplit {
fn weight(&self) -> f64 {
self.weight
}
fn size(&self) -> usize {
self.size()
}
fn smaller_part(&self) -> &fixedbitset::FixedBitSet {
self.smaller_part()
}
fn ntax(&self) -> usize {
self.ntax()
}
}