use std::borrow::Borrow;
use std::fmt::Debug;
use std::fmt::Display;
use std::hash::Hash;
use bitflags::bitflags;
use crate::parsers::nom_utils::NomCustomError;
use anyhow::Result;
use nom::IResult;
use std::io::Write;
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 + Hash + Eq + Sync + 'static {
type Type: Clone + Debug;
type ReverseWeight: Semiring + ReverseBack<Self>;
fn zero() -> Self;
fn one() -> Self;
fn new(value: Self::Type) -> Self;
fn plus<P: Borrow<Self>>(&self, rhs: P) -> Result<Self> {
let mut w = self.clone();
w.plus_assign(rhs)?;
Ok(w)
}
fn plus_assign<P: Borrow<Self>>(&mut self, rhs: P) -> Result<()>;
fn times<P: Borrow<Self>>(&self, rhs: P) -> Result<Self> {
let mut w = self.clone();
w.times_assign(rhs)?;
Ok(w)
}
fn times_assign<P: Borrow<Self>>(&mut self, rhs: P) -> Result<()>;
fn approx_equal<P: Borrow<Self>>(&self, rhs: P, delta: f32) -> bool;
fn value(&self) -> &Self::Type;
fn take_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 reverse(&self) -> Result<Self::ReverseWeight>;
fn properties() -> SemiringProperties;
}
pub trait ReverseBack<W> {
fn reverse_back(&self) -> Result<W>;
}
#[derive(Copy, Clone, PartialOrd, PartialEq)]
pub enum DivideType {
DivideLeft,
DivideRight,
DivideAny,
}
pub trait WeaklyDivisibleSemiring: Semiring {
fn divide_assign(&mut self, rhs: &Self, divide_type: DivideType) -> Result<()>;
fn divide(&self, rhs: &Self, divide_type: DivideType) -> Result<Self> {
let mut w = self.clone();
w.divide_assign(rhs, divide_type)?;
Ok(w)
}
}
pub trait CompleteSemiring: Semiring {}
pub trait StarSemiring: Semiring {
fn closure(&self) -> Self;
}
pub trait WeightQuantize: Semiring {
fn quantize_assign(&mut self, delta: f32) -> Result<()>;
fn quantize(&self, delta: f32) -> Result<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) -> Result<()> {
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 {
let w1 = *self.value();
let w2 = *other.value();
w1 <= (w2 + KDELTA) && w2 <= (w1 + KDELTA)
}
}
impl Hash for $semiring {
fn hash<H: Hasher>(&self, state: &mut H) {
self.value.hash(state)
}
}
};
}
pub trait SerializableSemiring: Semiring + Display {
fn weight_type() -> String;
fn parse_binary(i: &[u8]) -> IResult<&[u8], Self, NomCustomError<&[u8]>>;
fn write_binary<F: Write>(&self, file: &mut F) -> Result<()>;
fn parse_text(i: &str) -> IResult<&str, Self>;
fn write_text<F: Write>(&self, file: &mut F) -> Result<()> {
write!(file, "{}", self)?;
Ok(())
}
}