use fixedbitset::FixedBitSet;
use std::cmp::Ordering;
use std::fmt::{self, Display};
use std::hash::{Hash, Hasher};
#[derive(Debug, Clone)]
pub struct BiPartition {
pub a: FixedBitSet,
pub b: FixedBitSet,
}
impl BiPartition {
pub fn new(a: FixedBitSet, b: FixedBitSet) -> Self {
let ca = cardinality(&a);
let cb = cardinality(&b);
debug_assert!(ca > 0 && cb > 0, "invalid split: |A|={ca}, |B|={cb}");
let a_first = first_set_at_or_after(&a, 1).unwrap_or(usize::MAX);
let b_first = first_set_at_or_after(&b, 1).unwrap_or(usize::MAX);
if a_first < b_first {
Self { a, b }
} else {
Self { a: b, b: a }
}
}
pub fn ntax(&self) -> usize {
cardinality(&self.a) + cardinality(&self.b)
}
pub fn size(&self) -> usize {
cardinality(&self.a).min(cardinality(&self.b))
}
pub fn get_a(&self) -> &FixedBitSet {
&self.a
}
pub fn get_b(&self) -> &FixedBitSet {
&self.b
}
pub fn part_containing(&self, t: usize) -> &FixedBitSet {
if self.b.contains(t) { &self.b } else { &self.a }
}
pub fn part_not_containing(&self, t: usize) -> &FixedBitSet {
if !self.a.contains(t) {
&self.a
} else {
&self.b
}
}
pub fn smaller_part(&self) -> &FixedBitSet {
let ca = cardinality(&self.a);
let cb = cardinality(&self.b);
match ca.cmp(&cb) {
Ordering::Less => &self.a,
Ordering::Greater => &self.b,
Ordering::Equal => {
let af = first_set_at_or_after(&self.a, 1).unwrap_or(usize::MAX);
let bf = first_set_at_or_after(&self.b, 1).unwrap_or(usize::MAX);
if af < bf { &self.a } else { &self.b }
}
}
}
pub fn is_trivial(&self) -> bool {
cardinality(self.smaller_part()) == 1
}
}
impl PartialEq for BiPartition {
fn eq(&self, other: &Self) -> bool {
bitset_eq(&self.a, &other.a) && bitset_eq(&self.b, &other.b)
}
}
impl Eq for BiPartition {}
impl Hash for BiPartition {
fn hash<H: Hasher>(&self, state: &mut H) {
for i in self.a.ones() {
i.hash(state);
}
0usize.hash(state); for i in self.b.ones() {
i.hash(state);
}
}
}
impl PartialOrd for BiPartition {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for BiPartition {
fn cmp(&self, other: &Self) -> Ordering {
match compare_bitsets(&self.a, &other.a) {
Ordering::Equal => compare_bitsets(&self.b, &other.b),
ord => ord,
}
}
}
impl Display for BiPartition {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fn part_to_string(bs: &FixedBitSet) -> String {
let mut first = true;
let mut s = String::new();
for i in bs.ones() {
if i == 0 {
continue;
} if !first {
s.push(',');
} else {
first = false;
}
s.push_str(&i.to_string());
}
s
}
write!(
f,
"{{{}}} | {{{}}}",
part_to_string(&self.a),
part_to_string(&self.b)
)
}
}
fn cardinality(bs: &FixedBitSet) -> usize {
bs.ones().filter(|&i| i != 0).count()
}
fn first_set_at_or_after(bs: &FixedBitSet, start: usize) -> Option<usize> {
bs.ones().find(|&i| i >= start)
}
fn bitset_eq(a: &FixedBitSet, b: &FixedBitSet) -> bool {
let a_len = a.ones().count();
let b_len = b.ones().count();
if a_len != b_len {
return false;
}
for i in a.ones() {
if !b.contains(i) {
return false;
}
}
true
}
fn compare_bitsets(a: &FixedBitSet, b: &FixedBitSet) -> Ordering {
let mut ia = a.ones().filter(|&i| i != 0);
let mut ib = b.ones().filter(|&i| i != 0);
loop {
match (ia.next(), ib.next()) {
(Some(x), Some(y)) => {
if x != y {
return x.cmp(&y);
}
}
(None, Some(_)) => return Ordering::Less,
(Some(_), None) => return Ordering::Greater,
(None, None) => return Ordering::Equal,
}
}
}