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 UnionGallic;
impl GallicVariant for UnionGallic {
fn plus<W: Semiring>(
labels1: &[Label],
weight1: &W,
labels2: &[Label],
weight2: &W,
) -> (Vec<Label>, W) {
let common_labels = labels1
.iter()
.zip(labels2.iter())
.take_while(|(a, b)| a == b)
.map(|(a, _)| *a)
.collect();
let combined_weight = weight1.plus(weight2);
(common_labels, combined_weight)
}
fn variant_name() -> &'static str {
"Union"
}
fn properties<W: Semiring>() -> SemiringProperties {
let _weight_props = W::properties();
SemiringProperties {
left_semiring: true,
right_semiring: true,
commutative: false,
idempotent: false,
path: false,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::semiring::{ProbabilityWeight, TropicalWeight};
#[test]
fn test_union_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) = UnionGallic::plus(&labels1, &w1, &labels2, &w2);
assert_eq!(result_labels, vec![1, 2, 3]);
assert_eq!(*result_weight.value(), 1.0); }
#[test]
fn test_union_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) = UnionGallic::plus(&labels1, &w1, &labels2, &w2);
assert_eq!(result_labels, vec![1, 2]); assert_eq!(*result_weight.value(), 1.5);
}
#[test]
fn test_union_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) = UnionGallic::plus(&labels1, &w1, &labels2, &w2);
assert_eq!(result_labels, Vec::<Label>::new());
assert_eq!(*result_weight.value(), 2.0);
}
#[test]
fn test_union_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) = UnionGallic::plus(&labels1, &w1, &labels2, &w2);
assert_eq!(result_labels, Vec::<Label>::new());
assert_eq!(*result_weight.value(), 1.0);
}
#[test]
fn test_union_gallic_plus_with_probability() {
let labels1 = vec![5, 6, 7];
let labels2 = vec![5, 6, 8];
let w1 = ProbabilityWeight::new(0.3);
let w2 = ProbabilityWeight::new(0.5);
let (result_labels, result_weight) = UnionGallic::plus(&labels1, &w1, &labels2, &w2);
assert_eq!(result_labels, vec![5, 6]);
assert_eq!(*result_weight.value(), 0.8); }
#[test]
fn test_union_gallic_general_flexibility() {
let scenarios = vec![
(vec![1, 2, 3], vec![1, 2, 3], vec![1, 2, 3]), (vec![1, 2, 3], vec![1, 2, 4], vec![1, 2]), (vec![1, 2], vec![3, 4], vec![]), (vec![1], vec![1, 2, 3], vec![1]), ];
for (labels1, labels2, expected) in scenarios {
let w1 = TropicalWeight::new(1.0);
let w2 = TropicalWeight::new(2.0);
let (result_labels, _) = UnionGallic::plus(&labels1, &w1, &labels2, &w2);
assert_eq!(result_labels, expected);
}
}
#[test]
fn test_union_gallic_variant_name() {
assert_eq!(UnionGallic::variant_name(), "Union");
}
#[test]
fn test_union_gallic_properties() {
let props = UnionGallic::properties::<TropicalWeight>();
assert!(props.left_semiring);
assert!(props.right_semiring);
assert!(!props.commutative); assert!(!props.idempotent);
assert!(!props.path);
}
#[test]
fn test_union_gallic_not_functional() {
assert!(!UnionGallic::is_functional());
}
#[test]
fn test_union_gallic_similarity_to_left() {
let labels1 = vec![10, 20, 30];
let labels2 = vec![10, 20, 40];
let w1 = TropicalWeight::new(5.0);
let w2 = TropicalWeight::new(3.0);
let (result_labels, result_weight) = UnionGallic::plus(&labels1, &w1, &labels2, &w2);
assert_eq!(result_labels, vec![10, 20]);
assert_eq!(*result_weight.value(), 3.0);
}
#[test]
fn test_union_gallic_default_use_case() {
let labels1 = vec![1, 2];
let labels2 = vec![1, 3];
let w1 = TropicalWeight::new(2.0);
let w2 = TropicalWeight::new(4.0);
let (result_labels, result_weight) = UnionGallic::plus(&labels1, &w1, &labels2, &w2);
assert_eq!(result_labels, vec![1]); assert_eq!(*result_weight.value(), 2.0); }
}