use crate::arc::Arc;
use crate::fst::Label;
use crate::semiring::Semiring;
use std::collections::HashMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EncodeType {
EncodeLabelsAndWeights,
EncodeWeightsOnly,
EncodeLabelsOnly,
LabelsAndWeights,
Weights,
Labels,
}
#[derive(Debug, Clone)]
pub struct EncodeMapper<W: Semiring + Eq + std::hash::Hash> {
encode_type: EncodeType,
label_map: HashMap<(Label, Label), Label>,
weight_map: HashMap<W, u32>,
reverse_label_map: HashMap<Label, (Label, Label)>,
reverse_weight_map: HashMap<u32, W>,
original_olabel_map: HashMap<Label, Label>,
input_symbols: crate::utils::SymbolTable,
output_symbols: crate::utils::SymbolTable,
next_label: Label,
next_weight: u32,
}
impl<W: Semiring + Eq + std::hash::Hash> EncodeMapper<W> {
pub fn new(encode_type: EncodeType) -> Self {
Self {
encode_type,
label_map: HashMap::new(),
weight_map: HashMap::new(),
reverse_label_map: HashMap::new(),
reverse_weight_map: HashMap::new(),
original_olabel_map: HashMap::new(),
input_symbols: crate::utils::SymbolTable::new(),
output_symbols: crate::utils::SymbolTable::new(),
next_label: 1,
next_weight: 0,
}
}
pub fn encode_type(&self) -> EncodeType {
self.encode_type
}
pub fn size(&self) -> usize {
self.label_map.len() + self.weight_map.len()
}
pub fn encode(&mut self, arc: &Arc<W>) -> Arc<W> {
match self.encode_type {
EncodeType::EncodeLabelsAndWeights | EncodeType::LabelsAndWeights => {
let label = self.encode_labels(arc.ilabel, arc.olabel);
let weight_id = self.encode_weight(&arc.weight);
Arc::new(label, weight_id, W::one(), arc.nextstate)
}
EncodeType::EncodeWeightsOnly | EncodeType::Weights => {
let weight_id = self.encode_weight(&arc.weight);
self.original_olabel_map.insert(arc.ilabel, arc.olabel);
Arc::new(arc.ilabel, weight_id, W::one(), arc.nextstate)
}
EncodeType::EncodeLabelsOnly | EncodeType::Labels => {
let label = self.encode_labels(arc.ilabel, arc.olabel);
Arc::new(label, 0, arc.weight.clone(), arc.nextstate)
}
}
}
pub fn decode(&self, arc: &Arc<W>) -> Result<Arc<W>, &'static str> {
match self.encode_type {
EncodeType::EncodeLabelsAndWeights | EncodeType::LabelsAndWeights => {
let (ilabel, olabel) = self
.reverse_label_map
.get(&arc.ilabel)
.ok_or("Label not found in reverse mapping")?;
let weight = self
.reverse_weight_map
.get(&arc.olabel)
.ok_or("Weight not found in reverse mapping")?;
Ok(Arc::new(*ilabel, *olabel, weight.clone(), arc.nextstate))
}
EncodeType::EncodeWeightsOnly | EncodeType::Weights => {
let weight = self
.reverse_weight_map
.get(&arc.olabel)
.ok_or("Weight not found in reverse mapping")?;
let original_olabel = self
.original_olabel_map
.get(&arc.ilabel)
.ok_or("Original output label not found")?;
Ok(Arc::new(
arc.ilabel,
*original_olabel,
weight.clone(),
arc.nextstate,
))
}
EncodeType::EncodeLabelsOnly | EncodeType::Labels => {
let (ilabel, olabel) = self
.reverse_label_map
.get(&arc.ilabel)
.ok_or("Label not found in reverse mapping")?;
Ok(Arc::new(
*ilabel,
*olabel,
arc.weight.clone(),
arc.nextstate,
))
}
}
}
pub fn input_symbols(&self) -> &crate::utils::SymbolTable {
&self.input_symbols
}
pub fn output_symbols(&self) -> &crate::utils::SymbolTable {
&self.output_symbols
}
fn encode_labels(&mut self, ilabel: Label, olabel: Label) -> Label {
let key = (ilabel, olabel);
if let Some(&encoded_label) = self.label_map.get(&key) {
encoded_label
} else {
let encoded_label = self.next_label;
self.label_map.insert(key, encoded_label);
self.reverse_label_map.insert(encoded_label, key);
self.input_symbols.add_symbol(&format!("i{ilabel}"));
self.output_symbols.add_symbol(&format!("o{olabel}"));
self.next_label += 1;
encoded_label
}
}
fn encode_weight(&mut self, weight: &W) -> u32 {
if let Some(&id) = self.weight_map.get(weight) {
id
} else {
let id = self.next_weight;
self.weight_map.insert(weight.clone(), id);
self.reverse_weight_map.insert(id, weight.clone());
self.next_weight += 1;
id
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::arc::Arc;
use crate::semiring::TropicalWeight;
use num_traits::One;
#[test]
fn test_encode_mapper_creation() {
let mapper = EncodeMapper::<TropicalWeight>::new(EncodeType::Labels);
assert_eq!(mapper.encode_type(), EncodeType::Labels);
assert_eq!(mapper.size(), 0);
}
#[test]
fn test_encode_mapper_encode_arc() {
let mut mapper = EncodeMapper::<TropicalWeight>::new(EncodeType::Labels);
let arc = Arc::new(1, 2, TropicalWeight::new(3.0), 4);
let encoded_arc = mapper.encode(&arc);
assert_eq!(encoded_arc.nextstate, arc.nextstate);
assert_eq!(encoded_arc.weight, arc.weight);
if mapper.encode_type() == EncodeType::Labels {
assert!(encoded_arc.ilabel < u32::MAX);
assert!(encoded_arc.olabel < u32::MAX);
} else {
assert_eq!(encoded_arc.ilabel, arc.ilabel);
assert_eq!(encoded_arc.olabel, arc.olabel);
}
}
#[test]
fn test_encode_mapper_decode_arc() {
let mut mapper = EncodeMapper::<TropicalWeight>::new(EncodeType::Labels);
let original_arc = Arc::new(10, 20, TropicalWeight::new(5.0), 30);
let encoded_arc = mapper.encode(&original_arc);
let decoded_arc = mapper.decode(&encoded_arc).unwrap();
assert_eq!(decoded_arc.ilabel, original_arc.ilabel);
assert_eq!(decoded_arc.olabel, original_arc.olabel);
assert_eq!(decoded_arc.weight, original_arc.weight);
assert_eq!(decoded_arc.nextstate, original_arc.nextstate);
}
#[test]
fn test_encode_mapper_encode_types() {
let label_mapper = EncodeMapper::<TropicalWeight>::new(EncodeType::Labels);
let weights_mapper = EncodeMapper::<TropicalWeight>::new(EncodeType::Weights);
let both_mapper = EncodeMapper::<TropicalWeight>::new(EncodeType::LabelsAndWeights);
assert_eq!(label_mapper.encode_type(), EncodeType::Labels);
assert_eq!(weights_mapper.encode_type(), EncodeType::Weights);
assert_eq!(both_mapper.encode_type(), EncodeType::LabelsAndWeights);
}
#[test]
fn test_encode_mapper_consistency() {
let mut mapper = EncodeMapper::<TropicalWeight>::new(EncodeType::LabelsAndWeights);
let arc1 = Arc::new(1, 2, TropicalWeight::new(3.0), 4);
let arc2 = Arc::new(1, 2, TropicalWeight::new(3.0), 5);
let arc3 = Arc::new(1, 2, TropicalWeight::new(4.0), 4);
let encoded1 = mapper.encode(&arc1);
let encoded2 = mapper.encode(&arc2);
let encoded3 = mapper.encode(&arc3);
assert_eq!(encoded1.ilabel, encoded2.ilabel);
assert_eq!(encoded1.olabel, encoded2.olabel);
assert_ne!(encoded1.olabel, encoded3.olabel);
}
#[test]
fn test_encode_mapper_size() {
let mut mapper = EncodeMapper::<TropicalWeight>::new(EncodeType::Labels);
assert_eq!(mapper.size(), 0);
let arc1 = Arc::new(1, 2, TropicalWeight::new(3.0), 4);
mapper.encode(&arc1);
assert_eq!(mapper.size(), 1);
let arc2 = Arc::new(3, 4, TropicalWeight::new(5.0), 6);
mapper.encode(&arc2);
assert_eq!(mapper.size(), 2);
let arc3 = Arc::new(1, 2, TropicalWeight::new(7.0), 8);
mapper.encode(&arc3);
assert_eq!(mapper.size(), 2);
}
#[test]
fn test_encode_mapper_weights() {
let mut mapper = EncodeMapper::<TropicalWeight>::new(EncodeType::Weights);
let arc1 = Arc::new(1, 2, TropicalWeight::new(3.0), 4);
let arc2 = Arc::new(5, 6, TropicalWeight::new(3.0), 7);
let arc3 = Arc::new(8, 9, TropicalWeight::new(4.0), 10);
let encoded1 = mapper.encode(&arc1);
let encoded2 = mapper.encode(&arc2);
let encoded3 = mapper.encode(&arc3);
assert_eq!(encoded1.ilabel, arc1.ilabel);
assert_eq!(encoded2.ilabel, arc2.ilabel);
assert_eq!(encoded3.ilabel, arc3.ilabel);
assert_eq!(encoded1.olabel, encoded2.olabel);
assert_ne!(encoded1.olabel, encoded3.olabel);
}
#[test]
fn test_encode_mapper_symbol_tables() {
let mut mapper = EncodeMapper::<TropicalWeight>::new(EncodeType::Labels);
assert_eq!(mapper.input_symbols().size(), 1); assert_eq!(mapper.output_symbols().size(), 1);
let arc = Arc::new(1, 2, TropicalWeight::new(3.0), 4);
mapper.encode(&arc);
assert!(mapper.input_symbols().size() > 1);
assert!(mapper.output_symbols().size() > 1);
}
#[test]
fn test_encode_decode_labels_only() {
let mut mapper = EncodeMapper::<TropicalWeight>::new(EncodeType::EncodeLabelsOnly);
let arc1 = Arc::new(1, 2, TropicalWeight::new(3.0), 4);
let arc2 = Arc::new(1, 2, TropicalWeight::new(5.0), 6);
let arc3 = Arc::new(3, 4, TropicalWeight::new(3.0), 7);
let encoded1 = mapper.encode(&arc1);
let encoded2 = mapper.encode(&arc2);
let encoded3 = mapper.encode(&arc3);
assert_eq!(encoded1.ilabel, encoded2.ilabel);
assert_eq!(encoded1.olabel, encoded2.olabel);
assert_ne!(encoded1.ilabel, encoded3.ilabel);
assert_eq!(encoded1.weight, arc1.weight);
assert_eq!(encoded2.weight, arc2.weight);
let decoded1 = mapper.decode(&encoded1).unwrap();
let decoded2 = mapper.decode(&encoded2).unwrap();
let decoded3 = mapper.decode(&encoded3).unwrap();
assert_eq!(decoded1.ilabel, arc1.ilabel);
assert_eq!(decoded1.olabel, arc1.olabel);
assert_eq!(decoded1.weight, arc1.weight);
assert_eq!(decoded1.nextstate, arc1.nextstate);
assert_eq!(decoded2.ilabel, arc2.ilabel);
assert_eq!(decoded2.olabel, arc2.olabel);
assert_eq!(decoded2.weight, arc2.weight);
assert_eq!(decoded2.nextstate, arc2.nextstate);
assert_eq!(decoded3.ilabel, arc3.ilabel);
assert_eq!(decoded3.olabel, arc3.olabel);
assert_eq!(decoded3.weight, arc3.weight);
assert_eq!(decoded3.nextstate, arc3.nextstate);
}
#[test]
fn test_encode_decode_weights_only() {
let mut mapper = EncodeMapper::<TropicalWeight>::new(EncodeType::EncodeWeightsOnly);
let arc1 = Arc::new(1, 2, TropicalWeight::new(3.0), 4);
let arc2 = Arc::new(5, 6, TropicalWeight::new(3.0), 7);
let arc3 = Arc::new(1, 2, TropicalWeight::new(8.0), 9);
let encoded1 = mapper.encode(&arc1);
let encoded2 = mapper.encode(&arc2);
let encoded3 = mapper.encode(&arc3);
assert_eq!(encoded1.olabel, encoded2.olabel);
assert_ne!(encoded1.olabel, encoded3.olabel);
assert_eq!(encoded1.ilabel, arc1.ilabel);
assert_eq!(encoded2.ilabel, arc2.ilabel);
assert_eq!(encoded3.ilabel, arc3.ilabel);
assert_eq!(encoded1.weight, TropicalWeight::one());
assert_eq!(encoded2.weight, TropicalWeight::one());
assert_eq!(encoded3.weight, TropicalWeight::one());
let decoded1 = mapper.decode(&encoded1).unwrap();
let decoded2 = mapper.decode(&encoded2).unwrap();
let decoded3 = mapper.decode(&encoded3).unwrap();
assert_eq!(decoded1.ilabel, arc1.ilabel);
assert_eq!(decoded1.olabel, arc1.olabel);
assert_eq!(decoded1.weight, arc1.weight);
assert_eq!(decoded1.nextstate, arc1.nextstate);
assert_eq!(decoded2.ilabel, arc2.ilabel);
assert_eq!(decoded2.olabel, arc2.olabel);
assert_eq!(decoded2.weight, arc2.weight);
assert_eq!(decoded2.nextstate, arc2.nextstate);
assert_eq!(decoded3.ilabel, arc3.ilabel);
assert_eq!(decoded3.olabel, arc3.olabel);
assert_eq!(decoded3.weight, arc3.weight);
assert_eq!(decoded3.nextstate, arc3.nextstate);
}
#[test]
fn test_encode_decode_labels_and_weights() {
let mut mapper = EncodeMapper::<TropicalWeight>::new(EncodeType::EncodeLabelsAndWeights);
let arc1 = Arc::new(1, 2, TropicalWeight::new(3.0), 4);
let arc2 = Arc::new(1, 2, TropicalWeight::new(3.0), 5);
let arc3 = Arc::new(1, 2, TropicalWeight::new(6.0), 7);
let arc4 = Arc::new(8, 9, TropicalWeight::new(3.0), 10);
let encoded1 = mapper.encode(&arc1);
let encoded2 = mapper.encode(&arc2);
let encoded3 = mapper.encode(&arc3);
let encoded4 = mapper.encode(&arc4);
assert_eq!(encoded1.ilabel, encoded2.ilabel);
assert_eq!(encoded1.olabel, encoded2.olabel);
assert_ne!(encoded1.olabel, encoded3.olabel);
assert_ne!(encoded1.ilabel, encoded4.ilabel);
assert_eq!(encoded1.weight, TropicalWeight::one());
assert_eq!(encoded2.weight, TropicalWeight::one());
assert_eq!(encoded3.weight, TropicalWeight::one());
assert_eq!(encoded4.weight, TropicalWeight::one());
let decoded1 = mapper.decode(&encoded1).unwrap();
let decoded2 = mapper.decode(&encoded2).unwrap();
let decoded3 = mapper.decode(&encoded3).unwrap();
let decoded4 = mapper.decode(&encoded4).unwrap();
assert_eq!(decoded1.ilabel, arc1.ilabel);
assert_eq!(decoded1.olabel, arc1.olabel);
assert_eq!(decoded1.weight, arc1.weight);
assert_eq!(decoded1.nextstate, arc1.nextstate);
assert_eq!(decoded2.ilabel, arc2.ilabel);
assert_eq!(decoded2.olabel, arc2.olabel);
assert_eq!(decoded2.weight, arc2.weight);
assert_eq!(decoded2.nextstate, arc2.nextstate);
assert_eq!(decoded3.ilabel, arc3.ilabel);
assert_eq!(decoded3.olabel, arc3.olabel);
assert_eq!(decoded3.weight, arc3.weight);
assert_eq!(decoded3.nextstate, arc3.nextstate);
assert_eq!(decoded4.ilabel, arc4.ilabel);
assert_eq!(decoded4.olabel, arc4.olabel);
assert_eq!(decoded4.weight, arc4.weight);
assert_eq!(decoded4.nextstate, arc4.nextstate);
}
#[test]
fn test_encode_decode_error_cases() {
let mapper = EncodeMapper::<TropicalWeight>::new(EncodeType::EncodeLabelsOnly);
let invalid_arc = Arc::new(999, 0, TropicalWeight::new(1.0), 1);
let result = mapper.decode(&invalid_arc);
assert!(result.is_err());
assert_eq!(result.unwrap_err(), "Label not found in reverse mapping");
let weight_mapper = EncodeMapper::<TropicalWeight>::new(EncodeType::EncodeWeightsOnly);
let invalid_weight_arc = Arc::new(1, 999, TropicalWeight::one(), 1);
let result = weight_mapper.decode(&invalid_weight_arc);
assert!(result.is_err());
assert_eq!(result.unwrap_err(), "Weight not found in reverse mapping");
}
#[test]
fn test_encode_alias_types() {
let labels_mapper = EncodeMapper::<TropicalWeight>::new(EncodeType::Labels);
let encode_labels_mapper =
EncodeMapper::<TropicalWeight>::new(EncodeType::EncodeLabelsOnly);
assert_eq!(labels_mapper.encode_type(), EncodeType::Labels);
assert_eq!(
encode_labels_mapper.encode_type(),
EncodeType::EncodeLabelsOnly
);
let weights_mapper = EncodeMapper::<TropicalWeight>::new(EncodeType::Weights);
let encode_weights_mapper =
EncodeMapper::<TropicalWeight>::new(EncodeType::EncodeWeightsOnly);
assert_eq!(weights_mapper.encode_type(), EncodeType::Weights);
assert_eq!(
encode_weights_mapper.encode_type(),
EncodeType::EncodeWeightsOnly
);
let both_mapper = EncodeMapper::<TropicalWeight>::new(EncodeType::LabelsAndWeights);
let encode_both_mapper =
EncodeMapper::<TropicalWeight>::new(EncodeType::EncodeLabelsAndWeights);
assert_eq!(both_mapper.encode_type(), EncodeType::LabelsAndWeights);
assert_eq!(
encode_both_mapper.encode_type(),
EncodeType::EncodeLabelsAndWeights
);
}
#[test]
fn test_roundtrip_encoding_large_labels() {
let mut mapper = EncodeMapper::<TropicalWeight>::new(EncodeType::EncodeLabelsOnly);
let arc = Arc::new(u32::MAX - 1, u32::MAX, TropicalWeight::new(42.0), 100);
let encoded = mapper.encode(&arc);
let decoded = mapper.decode(&encoded).unwrap();
assert_eq!(decoded.ilabel, arc.ilabel);
assert_eq!(decoded.olabel, arc.olabel);
assert_eq!(decoded.weight, arc.weight);
assert_eq!(decoded.nextstate, arc.nextstate);
}
#[test]
fn test_multiple_encoding_sessions() {
let mut mapper = EncodeMapper::<TropicalWeight>::new(EncodeType::EncodeLabelsAndWeights);
let arc1 = Arc::new(1, 2, TropicalWeight::new(3.0), 4);
let encoded1 = mapper.encode(&arc1);
let decoded1 = mapper.decode(&encoded1).unwrap();
assert_eq!(decoded1.ilabel, arc1.ilabel);
let arc2 = Arc::new(5, 6, TropicalWeight::new(7.0), 8);
let encoded2 = mapper.encode(&arc2);
let decoded2 = mapper.decode(&encoded2).unwrap();
assert_eq!(decoded2.ilabel, arc2.ilabel);
let arc3 = Arc::new(1, 2, TropicalWeight::new(9.0), 10);
let encoded3 = mapper.encode(&arc3);
let decoded3 = mapper.decode(&encoded3).unwrap();
assert_eq!(decoded3.ilabel, arc3.ilabel);
assert_eq!(encoded1.ilabel, encoded3.ilabel); assert_ne!(encoded1.olabel, encoded3.olabel); }
}