use std::fmt::Debug;
use std::fmt::Display;
use std::hash::Hash;
use bitflags::bitflags;
use failure::Fallible;
bitflags! {
pub struct SemiringProperties: u32 {
const LEFT_SEMIRING = 0b00001;
const RIGHT_SEMIRING = 0b00010;
const COMMUTATIVE = 0b00100;
const IDEMPOTENT = 0b01000;
const PATH = 0b10000;
const SEMIRING = Self::LEFT_SEMIRING.bits | Self::RIGHT_SEMIRING.bits;
}
}
pub trait Semiring:
Clone + PartialEq + PartialOrd + Debug + Default + Display + AsRef<Self> + Hash + Eq
{
type Type;
fn zero() -> Self;
fn one() -> Self;
fn new(value: Self::Type) -> Self;
fn plus<P: AsRef<Self>>(&self, rhs: P) -> Fallible<Self> {
let mut w = self.clone();
w.plus_assign(rhs)?;
Ok(w)
}
fn plus_assign<P: AsRef<Self>>(&mut self, rhs: P) -> Fallible<()>;
fn times<P: AsRef<Self>>(&self, rhs: P) -> Fallible<Self> {
let mut w = self.clone();
w.times_assign(rhs)?;
Ok(w)
}
fn times_assign<P: AsRef<Self>>(&mut self, rhs: P) -> Fallible<()>;
fn value(&self) -> Self::Type;
fn set_value(&mut self, value: Self::Type);
fn is_one(&self) -> bool {
*self == Self::one()
}
fn is_zero(&self) -> bool {
*self == Self::zero()
}
fn properties() -> SemiringProperties;
}
#[derive(Copy, Clone, PartialOrd, PartialEq)]
pub enum DivideType {
DivideLeft,
DivideRight,
DivideAny,
}
pub trait WeaklyDivisibleSemiring: Semiring {
fn divide(&self, rhs: &Self, divide_type: DivideType) -> Fallible<Self>;
}
pub trait CompleteSemiring: Semiring {}
pub trait StarSemiring: Semiring {
fn closure(&self) -> Self;
}
pub trait WeightQuantize: Semiring {
fn quantize_assign(&mut self, delta: f32) -> Fallible<()>;
fn quantize(&self, delta: f32) -> Fallible<Self> {
let mut w = self.clone();
w.quantize_assign(delta)?;
Ok(w)
}
}
macro_rules! impl_quantize_f32 {
($semiring: ident) => {
impl WeightQuantize for $semiring {
fn quantize_assign(&mut self, delta: f32) -> Fallible<()> {
let v = self.value();
if v == f32::INFINITY || v == f32::NEG_INFINITY {
return Ok(());
}
self.set_value(((v / delta) + 0.5).floor() * delta);
Ok(())
}
}
};
}
macro_rules! display_semiring {
($semiring:tt) => {
use std::fmt;
impl fmt::Display for $semiring {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.value())?;
Ok(())
}
}
};
}
macro_rules! partial_eq_and_hash_f32 {
($semiring:tt) => {
impl PartialEq for $semiring {
fn eq(&self, other: &Self) -> bool {
self.quantize(KDELTA).unwrap().value() == other.quantize(KDELTA).unwrap().value()
}
}
impl Hash for $semiring {
fn hash<H: Hasher>(&self, state: &mut H) {
self.quantize(KDELTA).unwrap().value.hash(state);
}
}
};
}