use std::hash::Hash;
use super::StateId;
use crate::semiring::Semiring;
#[derive(Clone, Debug)]
pub struct WeightedTransition<L, W: Semiring> {
pub from: StateId,
pub input: Option<L>,
pub output: Option<L>,
pub to: StateId,
pub weight: W,
}
impl<L, W: Semiring> WeightedTransition<L, W> {
#[inline]
pub fn new(from: StateId, input: Option<L>, output: Option<L>, to: StateId, weight: W) -> Self {
Self {
from,
input,
output,
to,
weight,
}
}
#[inline]
pub fn epsilon(from: StateId, to: StateId, weight: W) -> Self {
Self {
from,
input: None,
output: None,
to,
weight,
}
}
#[inline]
pub fn is_epsilon_input(&self) -> bool {
self.input.is_none()
}
#[inline]
pub fn is_epsilon_output(&self) -> bool {
self.output.is_none()
}
#[inline]
pub fn is_epsilon(&self) -> bool {
self.input.is_none() && self.output.is_none()
}
}
impl<L: Clone, W: Semiring> WeightedTransition<L, W> {
#[inline]
pub fn with_weight(&self, weight: W) -> Self {
Self {
from: self.from,
input: self.input.clone(),
output: self.output.clone(),
to: self.to,
weight,
}
}
}
impl<L: PartialEq, W: Semiring> PartialEq for WeightedTransition<L, W> {
fn eq(&self, other: &Self) -> bool {
self.from == other.from
&& self.input == other.input
&& self.output == other.output
&& self.to == other.to
&& self.weight == other.weight
}
}
impl<L: Eq, W: Semiring> Eq for WeightedTransition<L, W> {}
impl<L: Hash, W: Semiring> Hash for WeightedTransition<L, W> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.from.hash(state);
self.input.hash(state);
self.output.hash(state);
self.to.hash(state);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::semiring::TropicalWeight;
#[test]
fn test_transition_creation() {
let t: WeightedTransition<char, TropicalWeight> =
WeightedTransition::new(0, Some('a'), Some('b'), 1, TropicalWeight::new(1.5));
assert_eq!(t.from, 0);
assert_eq!(t.input, Some('a'));
assert_eq!(t.output, Some('b'));
assert_eq!(t.to, 1);
assert_eq!(t.weight.value(), 1.5);
}
#[test]
fn test_epsilon_transition() {
let t: WeightedTransition<char, TropicalWeight> =
WeightedTransition::epsilon(0, 1, TropicalWeight::one());
assert!(t.is_epsilon());
assert!(t.is_epsilon_input());
assert!(t.is_epsilon_output());
}
#[test]
fn test_partial_epsilon() {
let t: WeightedTransition<char, TropicalWeight> =
WeightedTransition::new(0, Some('a'), None, 1, TropicalWeight::one());
assert!(!t.is_epsilon());
assert!(!t.is_epsilon_input());
assert!(t.is_epsilon_output());
}
}