use super::traits::*;
use core::fmt;
use core::ops::{Add, Mul};
use core::str::FromStr;
use num_traits::{One, Zero};
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct BooleanWeight(bool);
impl BooleanWeight {
pub const fn new(value: bool) -> Self {
Self(value)
}
}
impl fmt::Display for BooleanWeight {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let value = self.0;
write!(f, "{value}")
}
}
impl Zero for BooleanWeight {
fn zero() -> Self {
Self::new(false)
}
fn is_zero(&self) -> bool {
!self.0
}
}
impl One for BooleanWeight {
fn one() -> Self {
Self::new(true)
}
}
impl Add for BooleanWeight {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self(self.0 || rhs.0)
}
}
impl Mul for BooleanWeight {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
Self(self.0 && rhs.0)
}
}
impl Semiring for BooleanWeight {
type Value = bool;
fn new(value: Self::Value) -> Self {
Self::new(value)
}
fn value(&self) -> &Self::Value {
&self.0
}
fn properties() -> SemiringProperties {
SemiringProperties {
left_semiring: true,
right_semiring: true,
commutative: true,
idempotent: true,
path: true,
}
}
}
impl NaturallyOrderedSemiring for BooleanWeight {}
impl StarSemiring for BooleanWeight {
fn star(&self) -> Self {
Self::one()
}
}
impl FromStr for BooleanWeight {
type Err = std::str::ParseBoolError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
s.parse::<bool>().map(Self::new)
}
}
#[cfg(test)]
mod tests {
use super::*;
use num_traits::{One, Zero};
#[test]
fn test_boolean_weight_creation() {
let w_true = BooleanWeight::new(true);
let w_false = BooleanWeight::new(false);
assert!(*w_true.value());
assert!(!*w_false.value());
}
#[test]
fn test_boolean_zero_one() {
let zero = BooleanWeight::zero();
let one = BooleanWeight::one();
assert!(Semiring::is_zero(&zero));
assert!(Semiring::is_one(&one));
assert!(!*zero.value());
assert!(*one.value());
}
#[test]
fn test_boolean_addition() {
let w_true = BooleanWeight::new(true);
let w_false = BooleanWeight::new(false);
assert!(*w_true.plus(&w_false).value());
assert!(*w_false.plus(&w_true).value());
assert!(!*w_false.plus(&w_false).value());
assert!(*w_true.plus(&w_true).value());
}
#[test]
fn test_boolean_multiplication() {
let w_true = BooleanWeight::new(true);
let w_false = BooleanWeight::new(false);
assert!(!*w_true.times(&w_false).value());
assert!(!*w_false.times(&w_true).value());
assert!(!*w_false.times(&w_false).value());
assert!(*w_true.times(&w_true).value());
}
#[test]
fn test_boolean_idempotence() {
let w_true = BooleanWeight::new(true);
let w_false = BooleanWeight::new(false);
assert_eq!(w_true.plus(&w_true), w_true);
assert_eq!(w_false.plus(&w_false), w_false);
}
#[test]
fn test_boolean_display() {
let w_true = BooleanWeight::new(true);
let w_false = BooleanWeight::new(false);
assert_eq!(format!("{w_true}"), "true");
assert_eq!(format!("{w_false}"), "false");
}
#[test]
fn test_boolean_star() {
let w_true = BooleanWeight::new(true);
let w_false = BooleanWeight::new(false);
assert_eq!(w_true.star(), BooleanWeight::one());
assert_eq!(w_false.star(), BooleanWeight::one());
}
#[test]
fn test_boolean_properties() {
let props = BooleanWeight::properties();
assert!(props.left_semiring);
assert!(props.right_semiring);
assert!(props.commutative);
assert!(props.idempotent);
assert!(props.path);
}
#[test]
fn test_boolean_from_str() {
assert_eq!(
BooleanWeight::from_str("true").unwrap(),
BooleanWeight::new(true)
);
assert_eq!(
BooleanWeight::from_str("false").unwrap(),
BooleanWeight::new(false)
);
}
#[test]
fn test_boolean_operator_overloads() {
let w_true = BooleanWeight::new(true);
let w_false = BooleanWeight::new(false);
assert_eq!(w_true + w_false, BooleanWeight::new(true));
assert_eq!(w_false + w_false, BooleanWeight::new(false));
assert_eq!(w_true * w_false, BooleanWeight::new(false));
assert_eq!(w_true * w_true, BooleanWeight::new(true));
}
#[test]
fn test_boolean_identity_laws() {
let w = BooleanWeight::new(true);
let zero = BooleanWeight::zero();
let one = BooleanWeight::one();
assert_eq!(w + zero, w);
assert_eq!(zero + w, w);
assert_eq!(w * one, w);
assert_eq!(one * w, w);
assert!(Semiring::is_zero(&(w * zero)));
assert!(Semiring::is_zero(&(zero * w)));
}
#[test]
fn test_boolean_semiring_axioms() {
let a = BooleanWeight::new(true);
let b = BooleanWeight::new(false);
let c = BooleanWeight::new(true);
assert_eq!((a + b) + c, a + (b + c));
assert_eq!((a * b) * c, a * (b * c));
assert_eq!(a + b, b + a);
assert_eq!(a * b, b * a);
assert_eq!((a + b) * c, (a * c) + (b * c));
}
#[test]
fn test_boolean_correctness() {
let t = BooleanWeight::new(true);
let f = BooleanWeight::new(false);
assert_eq!(f + f, f);
assert_eq!(f + t, t);
assert_eq!(t + f, t);
assert_eq!(t + t, t);
assert_eq!(f * f, f);
assert_eq!(f * t, f);
assert_eq!(t * f, f);
assert_eq!(t * t, t);
}
}