Crate tetengo_lattice

Source
Expand description

§tetengo Lattice 1.4.1

A Viterbi search library.

The Viterbi search is a dynamic programming algorithm. It finds the most likely path in a lattice consisting of observed event nodes.

This library also provides the A* search algorithm for the lattice created by the Viterbi search.

§How to Use

Execute the cargo add command to add the “tetengo_lattice” library to your cargo package.

An entry for “tetengo_lattice” will be added to the “dependencies” section of Cargo.toml.

  • On Windows:
    • X:>cd \path\to\your\package
      X:>cargo add tetengo_lattice
  • On Linux:
    • $ cd /path/to/your/package
      $ cargo add tetengo_lattice

See the cargo document for details.

§Source Files

The source files for this library are available on GitHub.


Copyright (C) 2023-2025 kaoru https://www.tetengo.org/

This product is released under the MIT license. See the LICENSE file for details.

§Examples

/*!
 * The usage of tetengo_lattice
 */

mod usage {
    use std::hash::{DefaultHasher, Hash, Hasher};

    use tetengo_lattice::{
        Constraint, Entry, HashMapVocabulary, NBestIterator, Node, Path, StringInput, Vocabulary,
    };

    #[test]
    fn viterbi() {
        /*
            Makes the following lattice and searches it.

                    /-----[ab:AwaBizan]-----\
                   /  (7)      (9)      (1)  \
                  /                           \
                 /       (2)   (4)   (7)       \
            [BOS]-----[a:Alpha]---[b:Bravo]-----[EOS]
                 \ (3)         \ /(1)      (2) /
                  \(1)          X             /(6)
                   \           / \(5)        /
                    `-[a:Alice]---[b:Bob]---'
                         (1)   (9)  (8)
            Path                         Cost
            [BOS]-[Alice]-[Bravo]-[EOS]  1+1+1+7+2=12
            [BOS]---[AwaBizan]----[EOS]  7+9+1    =17
            [BOS]-[Alpha]-[Bravo]-[EOS]  3+2+4+7+2=18
            [BOS]-[Alpha]-[Bob]---[EOS]  3+2+5+8+6=24
            [BOS]-[Alice]-[Bob]---[EOS]  1+1+9+8+6=25
        */

        // Builds a vocabulary.
        let vocabulary = build_vocabulary();

        // Creates an object for a lattice.
        let mut lattice = tetengo_lattice::lattice::Lattice::new(vocabulary.as_ref());

        // Enters key characters to construct the lattice.
        let _ignored = lattice.push_back(Box::new(StringInput::new(String::from("a"))));
        let _ignored = lattice.push_back(Box::new(StringInput::new(String::from("b"))));

        // Finishes the lattice construction.
        let eos = lattice.settle().unwrap();

        // Creates an iterator to enumerate the paths in the lattice.
        let iterator = NBestIterator::new(&lattice, eos, Box::new(Constraint::new()));

        // Enumerates the paths.
        let paths = iterator.map(|path| to_string(&path)).collect::<Vec<_>>();
        let expected = vec![
            String::from("[BOS]-[Alice]-[Bravo]-[EOS] (12)"),
            String::from("[BOS]-[AwaBizan]-[EOS] (17)"),
            String::from("[BOS]-[Alpha]-[Bravo]-[EOS] (18)"),
            String::from("[BOS]-[Alpha]-[Bob]-[EOS] (24)"),
            String::from("[BOS]-[Alice]-[Bob]-[EOS] (25)"),
        ];
        assert_eq!(paths, expected);
    }

    fn build_vocabulary() -> Box<dyn Vocabulary> {
        // The contents of the vocabulary.
        let entries = [
            Entry::new(
                Box::new(StringInput::new(String::from("a"))),
                Box::new(String::from("Alpha")),
                2,
            ),
            Entry::new(
                Box::new(StringInput::new(String::from("b"))),
                Box::new(String::from("Bravo")),
                7,
            ),
            Entry::new(
                Box::new(StringInput::new(String::from("a"))),
                Box::new(String::from("Alice")),
                1,
            ),
            Entry::new(
                Box::new(StringInput::new(String::from("b"))),
                Box::new(String::from("Bob")),
                8,
            ),
            Entry::new(
                Box::new(StringInput::new(String::from("ab"))),
                Box::new(String::from("AwaBizan")),
                9,
            ),
        ];
        let entry_mappings = vec![
            (
                String::from("a"),
                vec![entries[0].clone(), entries[2].clone()],
            ),
            (
                String::from("b"),
                vec![entries[1].clone(), entries[3].clone()],
            ),
            (String::from("ab"), vec![entries[4].clone()]),
        ];
        let connections = vec![
            ((Entry::BosEos, entries[0].clone()), 3),
            ((Entry::BosEos, entries[2].clone()), 1),
            ((entries[0].clone(), entries[1].clone()), 4),
            ((entries[2].clone(), entries[1].clone()), 1),
            ((entries[0].clone(), entries[3].clone()), 5),
            ((entries[2].clone(), entries[3].clone()), 9),
            ((entries[1].clone(), Entry::BosEos), 2),
            ((entries[3].clone(), Entry::BosEos), 6),
            ((Entry::BosEos, entries[4].clone()), 7),
            ((entries[4].clone(), Entry::BosEos), 1),
        ];

        // Returns a vocabulary implemented with hash tables.
        Box::new(HashMapVocabulary::new(
            entry_mappings,
            connections,
            &|entry| {
                let mut hasher = DefaultHasher::new();
                hasher.write_u64(if let Some(key) = entry.key() {
                    key.hash_value()
                } else {
                    0
                });
                value_of_entry(entry).hash(&mut hasher);
                hasher.finish()
            },
            &|entry1, entry2| {
                let equal_keys = if let (Some(key1), Some(key2)) = (entry1.key(), entry2.key()) {
                    key1.equal_to(key2)
                } else {
                    entry1.key().is_none() && entry2.key().is_none()
                };
                if !equal_keys {
                    return false;
                }
                value_of_entry(entry1) == value_of_entry(entry2)
            },
        ))
    }

    fn to_string(path: &Path) -> String {
        // Each path object holds the nodes that make up itself, and the whole cost.
        let mut result = String::new();
        for node in path.nodes() {
            if !result.is_empty() {
                result += "-";
            }
            result += format!("[{}]", value_of_node(node, result.is_empty())).as_str();
        }
        result += format!(" ({})", path.cost()).as_str();
        result
    }

    fn value_of_node(node: &Node, first: bool) -> String {
        if let Some(value) = node.value() {
            // The value is stored in the Any object.
            value.downcast_ref::<String>().unwrap().clone()
        } else if first {
            String::from("BOS")
        } else {
            String::from("EOS")
        }
    }

    fn value_of_entry(entry: &Entry) -> String {
        // The value is stored in the Any object.
        if let Some(value) = entry.value() {
            value.downcast_ref::<String>().unwrap().clone()
        } else {
            String::new()
        }
    }
}

Re-exports§

pub use connection::Connection;
pub use constraint::Constraint;
pub use constraint_element::ConstraintElement;
pub use entry::Entry;
pub use error::Error;
pub use hash_map_vocabulary::HashMapVocabulary;
pub use input::Input;
pub use lattice::Lattice;
pub use n_best_iterator::NBestIterator;
pub use node::Node;
pub use node_constraint_element::NodeConstraintElement;
pub use path::Path;
pub use string_input::StringInput;
pub use vocabulary::Vocabulary;
pub use wildcard_constraint_element::WildcardConstraintElement;

Modules§

connection
A connection.
constraint
A constraint.
constraint_element
A constraint element.
entry
An entry.
error
An error.
hash_map_vocabulary
A hash map vocabulary.
input
An input.
lattice
A lattice.
n_best_iterator
An N-best lattice path iterator.
node
A node.
node_constraint_element
A node constraint element.
path
A path.
string_input
A string input.
vocabulary
A vocabulary.
wildcard_constraint_element
A wildcard constraint element.