mod feature;
mod string;
mod string_astar;
mod tag_string;
mod tag_tree;
mod tree;
use crate::{BottomUpTa, DetBottomUpTa, Signature, Symbol, VisualRepresentation};
use packed_term_arena::tree::{Tree, TreeArena};
use std::hash::Hash;
pub use string::{
SentenceSxHeuristic, Span, StringAlgebra, StringDecompositionAutomaton, UniversalSxHeuristic,
};
pub(crate) use string::{SpanProductSibling, SpanProductSiblingFinder};
pub(crate) use string_astar::{
SpanAstarLeftIndex, SpanBinarySiblingGroup, SpanInterner, StringAstarSource,
string_fallback_rules,
};
pub use tag_string::{
CONC11, CONC12, CONC21, TAG_E, TAG_EE, TagSpan, TagStringAlgebra,
TagStringDecompositionAutomaton, TagStringValue, WRAP21, WRAP22,
};
pub use tag_tree::{
BinarizedTagTreeDecompositionAutomaton, BinarizedTagTreeState, TAG_HOLE, TAG_SUBSTITUTE,
TagTreeAlgebra, TagTreeContext, TagTreeDecompositionAutomaton,
};
pub use tree::{APPEND_SYMBOL, Binarizing, TreeAlgebra, TreeValue};
pub trait Algebra {
type InternalValue: Clone + Eq + Hash;
type Value;
type ParseError;
fn signature(&self) -> &Signature;
fn evaluate(
&self,
symbol: Symbol,
children: &[Self::InternalValue],
) -> Option<Self::InternalValue>;
fn parse_object(&mut self, input: &str) -> Result<Self::InternalValue, Self::ParseError>;
fn to_external(&self, value: &Self::InternalValue) -> Self::Value;
fn visualize(&self, value: &Self::Value) -> VisualRepresentation;
fn evaluate_term_internal(
&self,
arena: &TreeArena<Symbol>,
root: Tree,
) -> Option<Self::InternalValue> {
let children: Vec<Self::InternalValue> = arena
.get_children(root)
.iter()
.map(|&child| self.evaluate_term_internal(arena, child))
.collect::<Option<_>>()?;
self.evaluate(*arena.get_label(root), &children)
}
fn evaluate_term(&self, arena: &TreeArena<Symbol>, root: Tree) -> Option<Self::Value> {
Some(self.to_external(&self.evaluate_term_internal(arena, root)?))
}
fn is_valid_value(&self, _value: &Self::InternalValue) -> bool {
true
}
fn decompose_default(
&self,
value: Self::InternalValue,
) -> EvaluatingDecompositionAutomaton<'_, Self>
where
Self: Sized,
{
EvaluatingDecompositionAutomaton::new(self, value)
}
}
pub struct EvaluatingDecompositionAutomaton<'a, A: Algebra> {
algebra: &'a A,
accepting: A::InternalValue,
}
impl<'a, A: Algebra> EvaluatingDecompositionAutomaton<'a, A> {
pub fn new(algebra: &'a A, accepting: A::InternalValue) -> Self {
Self { algebra, accepting }
}
}
impl<A: Algebra> BottomUpTa for EvaluatingDecompositionAutomaton<'_, A> {
type State = A::InternalValue;
fn step(&self, f: Symbol, children: &[Self::State], out: &mut dyn FnMut(Self::State)) {
if self.algebra.signature().arity(f) != children.len() {
return;
}
let Some(value) = self.algebra.evaluate(f, children) else {
return;
};
if self.algebra.is_valid_value(&value) {
out(value);
}
}
fn is_accepting(&self, q: &Self::State) -> bool {
q == &self.accepting
}
}
impl<A: Algebra> DetBottomUpTa for EvaluatingDecompositionAutomaton<'_, A> {
fn step_det(&self, f: Symbol, children: &[Self::State]) -> Option<Self::State> {
if self.algebra.signature().arity(f) != children.len() {
return None;
}
let value = self.algebra.evaluate(f, children)?;
self.algebra.is_valid_value(&value).then_some(value)
}
}
pub use feature::{
FS_EMBED_PREFIX, FS_PROJECT_PREFIX, FS_REMAP_PREFIX, FS_UNIFY, FeatureStructure,
FeatureStructureAlgebra, FeatureStructureAttribute, FeatureStructureFilter,
FeatureStructureNode, FeatureStructureNodeId, FeatureStructureParseError,
};
#[cfg(test)]
mod tests {
use super::*;
use packed_term_arena::tree::TreeArena;
#[derive(Clone)]
struct Tiny {
signature: Signature,
zero: Symbol,
inc: Symbol,
}
impl Tiny {
fn new() -> Self {
let mut signature = Signature::new();
let zero = signature.intern("zero".to_owned(), 0).unwrap();
let inc = signature.intern("inc".to_owned(), 1).unwrap();
Self {
signature,
zero,
inc,
}
}
}
impl Algebra for Tiny {
type InternalValue = u8;
type Value = u8;
type ParseError = std::num::ParseIntError;
fn signature(&self) -> &Signature {
&self.signature
}
fn evaluate(
&self,
symbol: Symbol,
children: &[Self::InternalValue],
) -> Option<Self::InternalValue> {
match (symbol, children) {
(s, []) if s == self.zero => Some(0),
(s, [x]) if s == self.inc => Some(x + 1),
_ => None,
}
}
fn parse_object(&mut self, input: &str) -> Result<Self::InternalValue, Self::ParseError> {
input.parse()
}
fn to_external(&self, value: &Self::InternalValue) -> Self::Value {
*value
}
fn visualize(&self, value: &Self::Value) -> VisualRepresentation {
VisualRepresentation::Text(value.to_string())
}
}
#[test]
fn default_decomposition_evaluates_bottom_up() {
let algebra = Tiny::new();
let decomp = algebra.decompose_default(2);
let zero = decomp.step_det(algebra.zero, &[]).unwrap();
let one = decomp.step_det(algebra.inc, &[zero]).unwrap();
let two = decomp.step_det(algebra.inc, &[one]).unwrap();
assert!(!decomp.is_accepting(&one));
assert!(decomp.is_accepting(&two));
assert_eq!(decomp.step_det(algebra.zero, &[two]), None);
}
#[test]
fn built_in_algebras_choose_structured_or_text_visualizations() {
let string = StringAlgebra::new();
assert!(matches!(
string.visualize(&vec!["hello".to_owned(), "world".to_owned()]),
VisualRepresentation::Text(text) if text == "hello world"
));
let tree = TreeAlgebra::tree(Signature::new());
let mut arena = TreeArena::new();
let root = arena.add_node("root".to_owned(), Vec::new());
let value = TreeValue::new(arena, root);
assert!(matches!(
tree.visualize(&value),
VisualRepresentation::Tree(_)
));
let feature = FeatureStructureAlgebra::with_signature(Signature::new());
let value = FeatureStructure::parse("[number: singular]").unwrap();
assert!(matches!(
feature.visualize(&value),
VisualRepresentation::FeatureStructure(_)
));
}
}