use crate::fst::Label;
use crate::semiring::gallic::variant::GallicVariant;
use crate::semiring::{Semiring, SemiringProperties};
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct MinGallic;
impl GallicVariant for MinGallic {
fn plus<W: Semiring>(
labels1: &[Label],
weight1: &W,
labels2: &[Label],
weight2: &W,
) -> (Vec<Label>, W) {
match weight1.partial_cmp(weight2) {
Some(std::cmp::Ordering::Less) => {
(labels1.to_vec(), weight1.clone())
}
Some(std::cmp::Ordering::Greater) => {
(labels2.to_vec(), weight2.clone())
}
Some(std::cmp::Ordering::Equal) | None => {
(labels1.to_vec(), weight1.clone())
}
}
}
fn variant_name() -> &'static str {
"Min"
}
fn properties<W: Semiring>() -> SemiringProperties {
let weight_props = W::properties();
SemiringProperties {
left_semiring: true,
right_semiring: true,
commutative: weight_props.commutative,
idempotent: true,
path: true,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::semiring::{ProbabilityWeight, TropicalWeight};
#[test]
fn test_min_gallic_plus_first_smaller() {
let labels1 = vec![1, 2, 3];
let labels2 = vec![4, 5, 6];
let w1 = TropicalWeight::new(1.0); let w2 = TropicalWeight::new(2.0);
let (result_labels, result_weight) = MinGallic::plus(&labels1, &w1, &labels2, &w2);
assert_eq!(result_labels, vec![1, 2, 3]); assert_eq!(*result_weight.value(), 1.0);
}
#[test]
fn test_min_gallic_plus_second_smaller() {
let labels1 = vec![1, 2, 3];
let labels2 = vec![4, 5, 6];
let w1 = TropicalWeight::new(5.0);
let w2 = TropicalWeight::new(2.0);
let (result_labels, result_weight) = MinGallic::plus(&labels1, &w1, &labels2, &w2);
assert_eq!(result_labels, vec![4, 5, 6]); assert_eq!(*result_weight.value(), 2.0);
}
#[test]
fn test_min_gallic_plus_equal_weights() {
let labels1 = vec![1, 2];
let labels2 = vec![3, 4];
let w1 = TropicalWeight::new(5.0);
let w2 = TropicalWeight::new(5.0);
let (result_labels, result_weight) = MinGallic::plus(&labels1, &w1, &labels2, &w2);
assert_eq!(result_labels, vec![1, 2]);
assert_eq!(*result_weight.value(), 5.0);
}
#[test]
fn test_min_gallic_plus_with_probability() {
let labels1 = vec![10, 20];
let labels2 = vec![30, 40];
let w1 = ProbabilityWeight::new(0.8); let w2 = ProbabilityWeight::new(0.3);
let (result_labels, _result_weight) = MinGallic::plus(&labels1, &w1, &labels2, &w2);
assert_eq!(result_labels, vec![30, 40]); }
#[test]
fn test_min_gallic_plus_empty_labels() {
let labels1: Vec<Label> = vec![];
let labels2 = vec![1, 2];
let w1 = TropicalWeight::new(1.0); let w2 = TropicalWeight::new(3.0);
let (result_labels, result_weight) = MinGallic::plus(&labels1, &w1, &labels2, &w2);
assert_eq!(result_labels, Vec::<Label>::new());
assert_eq!(*result_weight.value(), 1.0);
}
#[test]
fn test_min_gallic_idempotent() {
let labels = vec![5, 6, 7];
let w = TropicalWeight::new(2.0);
let (result_labels, result_weight) = MinGallic::plus(&labels, &w, &labels, &w);
assert_eq!(result_labels, vec![5, 6, 7]);
assert_eq!(*result_weight.value(), 2.0);
}
#[test]
fn test_min_gallic_variant_name() {
assert_eq!(MinGallic::variant_name(), "Min");
}
#[test]
fn test_min_gallic_properties() {
let props = MinGallic::properties::<TropicalWeight>();
assert!(props.left_semiring);
assert!(props.right_semiring);
assert!(props.commutative); assert!(props.idempotent); assert!(props.path); }
#[test]
fn test_min_gallic_path_property() {
let labels1 = vec![1, 2, 3];
let labels2 = vec![4, 5, 6];
let w1 = TropicalWeight::new(2.0);
let w2 = TropicalWeight::new(3.0);
let (result_labels, _) = MinGallic::plus(&labels1, &w1, &labels2, &w2);
assert!(result_labels == labels1 || result_labels == labels2);
}
#[test]
fn test_min_gallic_deterministic_tie_breaking() {
let labels1 = vec![1];
let labels2 = vec![2];
let w = TropicalWeight::new(5.0);
let (result1, _) = MinGallic::plus(&labels1, &w, &labels2, &w);
let (result2, _) = MinGallic::plus(&labels1, &w, &labels2, &w);
let (result3, _) = MinGallic::plus(&labels1, &w, &labels2, &w);
assert_eq!(result1, result2);
assert_eq!(result2, result3);
assert_eq!(result1, vec![1]); }
#[test]
fn test_min_gallic_not_functional() {
assert!(!MinGallic::is_functional());
}
}