use crate::fst::Label;
use crate::semiring::gallic::variant::{longest_common_prefix, GallicVariant};
use crate::semiring::{Semiring, SemiringProperties};
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct LeftGallic;
impl GallicVariant for LeftGallic {
fn plus<W: Semiring>(
labels1: &[Label],
weight1: &W,
labels2: &[Label],
weight2: &W,
) -> (Vec<Label>, W) {
let common_labels = longest_common_prefix(labels1, labels2);
let combined_weight = weight1.plus(weight2);
(common_labels, combined_weight)
}
fn variant_name() -> &'static str {
"Left"
}
fn properties<W: Semiring>() -> SemiringProperties {
SemiringProperties {
left_semiring: true,
right_semiring: true,
commutative: false,
idempotent: false,
path: false,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::semiring::TropicalWeight;
use num_traits::Zero;
#[test]
fn test_left_gallic_plus_identical_labels() {
let labels1 = vec![1, 2, 3];
let labels2 = vec![1, 2, 3];
let w1 = TropicalWeight::new(1.0);
let w2 = TropicalWeight::new(2.0);
let (result_labels, result_weight) = LeftGallic::plus(&labels1, &w1, &labels2, &w2);
assert_eq!(result_labels, vec![1, 2, 3]); assert_eq!(*result_weight.value(), 1.0); }
#[test]
fn test_left_gallic_plus_partial_overlap() {
let labels1 = vec![1, 2, 3, 4];
let labels2 = vec![1, 2, 5, 6];
let w1 = TropicalWeight::new(3.0);
let w2 = TropicalWeight::new(1.5);
let (result_labels, result_weight) = LeftGallic::plus(&labels1, &w1, &labels2, &w2);
assert_eq!(result_labels, vec![1, 2]); assert_eq!(*result_weight.value(), 1.5); }
#[test]
fn test_left_gallic_plus_no_overlap() {
let labels1 = vec![1, 2];
let labels2 = vec![3, 4];
let w1 = TropicalWeight::new(2.0);
let w2 = TropicalWeight::new(3.0);
let (result_labels, result_weight) = LeftGallic::plus(&labels1, &w1, &labels2, &w2);
assert_eq!(result_labels, Vec::<Label>::new()); assert_eq!(*result_weight.value(), 2.0); }
#[test]
fn test_left_gallic_plus_empty_labels() {
let labels1: Vec<Label> = vec![];
let labels2 = vec![1, 2];
let w1 = TropicalWeight::new(1.0);
let w2 = TropicalWeight::new(2.0);
let (result_labels, result_weight) = LeftGallic::plus(&labels1, &w1, &labels2, &w2);
assert_eq!(result_labels, Vec::<Label>::new());
assert_eq!(*result_weight.value(), 1.0);
}
#[test]
fn test_left_gallic_plus_one_prefix_of_other() {
let labels1 = vec![1, 2];
let labels2 = vec![1, 2, 3, 4];
let w1 = TropicalWeight::new(5.0);
let w2 = TropicalWeight::new(3.0);
let (result_labels, result_weight) = LeftGallic::plus(&labels1, &w1, &labels2, &w2);
assert_eq!(result_labels, vec![1, 2]); assert_eq!(*result_weight.value(), 3.0);
}
#[test]
fn test_left_gallic_plus_with_zero_weight() {
let labels1 = vec![1, 2, 3];
let labels2 = vec![1, 2, 4];
let w1 = TropicalWeight::zero(); let w2 = TropicalWeight::new(2.0);
let (result_labels, result_weight) = LeftGallic::plus(&labels1, &w1, &labels2, &w2);
assert_eq!(result_labels, vec![1, 2]);
assert_eq!(*result_weight.value(), 2.0); }
#[test]
fn test_left_gallic_variant_name() {
assert_eq!(LeftGallic::variant_name(), "Left");
}
#[test]
fn test_left_gallic_properties() {
let props = LeftGallic::properties::<TropicalWeight>();
assert!(props.left_semiring);
assert!(props.right_semiring);
assert!(!props.commutative); assert!(!props.idempotent); assert!(!props.path); }
#[test]
fn test_left_gallic_not_commutative() {
let labels1 = vec![1, 2, 3];
let labels2 = vec![1, 2, 4];
let w1 = TropicalWeight::new(1.0);
let w2 = TropicalWeight::new(1.0);
let (result1, weight1) = LeftGallic::plus(&labels1, &w1, &labels2, &w2);
let (result2, weight2) = LeftGallic::plus(&labels2, &w2, &labels1, &w1);
assert_eq!(result1, result2);
assert_eq!(weight1, weight2);
}
#[test]
fn test_left_gallic_functional_flag() {
assert!(!LeftGallic::is_functional());
}
#[test]
fn test_left_gallic_times_commutative() {
assert!(!LeftGallic::times_commutative());
}
}