1use super::{Algebra, Span};
7use crate::{
8 BottomUpTa, CondensedTa, DisplayCodec, FxHashMap, IndexedBottomUpTa, OutputCodec, Signature,
9 StateUniverse, Symbol, SymbolSet, TextVisualizationCodec, TopDownTa, VisualRepresentation,
10};
11use std::{convert::Infallible, fmt};
12
13pub const CONC11: &str = "*CONC11*";
15pub const CONC12: &str = "*CONC12*";
17pub const CONC21: &str = "*CONC21*";
19pub const WRAP21: &str = "*WRAP21*";
21pub const WRAP22: &str = "*WRAP22*";
23pub const TAG_E: &str = "*E*";
25pub const TAG_EE: &str = "*EE*";
27
28#[derive(Clone, Debug, PartialEq, Eq, Hash)]
30pub enum TagStringValue<T> {
31 String(Vec<T>),
33 Pair(Vec<T>, Vec<T>),
35}
36
37impl<T: fmt::Display> fmt::Display for TagStringValue<T> {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 fn words<T: fmt::Display>(f: &mut fmt::Formatter<'_>, values: &[T]) -> fmt::Result {
40 for (index, value) in values.iter().enumerate() {
41 if index > 0 {
42 f.write_str(" ")?;
43 }
44 write!(f, "{value}")?;
45 }
46 Ok(())
47 }
48
49 match self {
50 Self::String(value) => words(f, value),
51 Self::Pair(left, right) => {
52 f.write_str("[")?;
53 words(f, left)?;
54 f.write_str(" / ")?;
55 words(f, right)?;
56 f.write_str("]")
57 }
58 }
59 }
60}
61
62#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
63enum Operation {
64 Conc11,
65 Conc12,
66 Conc21,
67 Wrap21,
68 Wrap22,
69 E,
70 Ee,
71}
72
73#[derive(Clone, Debug)]
75pub struct TagStringAlgebra {
76 signature: Signature,
77 operations: FxHashMap<Symbol, Operation>,
78 display_codec: TextVisualizationCodec<DisplayCodec>,
79}
80
81impl TagStringAlgebra {
82 pub fn new() -> Self {
84 Self::with_signature(Signature::new())
85 }
86
87 pub fn with_signature(mut signature: Signature) -> Self {
89 let mut operations = FxHashMap::default();
90 for (name, arity, operation) in [
91 (CONC11, 2, Operation::Conc11),
92 (CONC12, 2, Operation::Conc12),
93 (CONC21, 2, Operation::Conc21),
94 (WRAP21, 2, Operation::Wrap21),
95 (WRAP22, 2, Operation::Wrap22),
96 (TAG_E, 0, Operation::E),
97 (TAG_EE, 0, Operation::Ee),
98 ] {
99 let symbol = signature.intern(name.to_owned(), arity).unwrap();
100 operations.insert(symbol, operation);
101 }
102 Self {
103 signature,
104 operations,
105 display_codec: TextVisualizationCodec::new(DisplayCodec),
106 }
107 }
108
109 pub fn intern_word(&mut self, word: impl Into<String>) -> Symbol {
111 self.signature.intern(word.into(), 0).unwrap()
112 }
113
114 pub fn operation_symbol(&self, name: &str) -> Option<Symbol> {
116 self.signature.get(name)
117 }
118
119 pub fn parse_string(&mut self, input: &str) -> TagStringValue<Symbol> {
121 TagStringValue::String(
122 input
123 .split_whitespace()
124 .map(|word| self.intern_word(word.to_owned()))
125 .collect(),
126 )
127 }
128
129 pub fn decompose(
133 &self,
134 value: TagStringValue<Symbol>,
135 ) -> Option<TagStringDecompositionAutomaton> {
136 let TagStringValue::String(words) = value else {
137 return None;
138 };
139 Some(TagStringDecompositionAutomaton::new(
140 self.operations.clone(),
141 words,
142 ))
143 }
144}
145
146impl Default for TagStringAlgebra {
147 fn default() -> Self {
148 Self::new()
149 }
150}
151
152fn append<T: Clone>(left: &[T], right: &[T]) -> Vec<T> {
153 let mut result = Vec::with_capacity(left.len() + right.len());
154 result.extend_from_slice(left);
155 result.extend_from_slice(right);
156 result
157}
158
159impl Algebra for TagStringAlgebra {
160 type InternalValue = TagStringValue<Symbol>;
161 type Value = TagStringValue<String>;
162 type ParseError = Infallible;
163
164 fn signature(&self) -> &Signature {
165 &self.signature
166 }
167
168 fn evaluate(
169 &self,
170 symbol: Symbol,
171 children: &[Self::InternalValue],
172 ) -> Option<Self::InternalValue> {
173 use TagStringValue::{Pair, String as One};
174 match self.operations.get(&symbol).copied() {
175 Some(Operation::Conc11) => match children {
176 [One(left), One(right)] => Some(One(append(left, right))),
177 _ => None,
178 },
179 Some(Operation::Conc12) => match children {
180 [One(first), Pair(left, right)] => Some(Pair(append(first, left), right.clone())),
181 _ => None,
182 },
183 Some(Operation::Conc21) => match children {
184 [Pair(left, right), One(second)] => Some(Pair(left.clone(), append(right, second))),
185 _ => None,
186 },
187 Some(Operation::Wrap21) => match children {
188 [Pair(left, right), One(middle)] => Some(One(append(&append(left, middle), right))),
189 _ => None,
190 },
191 Some(Operation::Wrap22) => match children {
192 [
193 Pair(first_left, first_right),
194 Pair(second_left, second_right),
195 ] => Some(Pair(
196 append(first_left, second_left),
197 append(second_right, first_right),
198 )),
199 _ => None,
200 },
201 Some(Operation::E) if children.is_empty() => Some(One(Vec::new())),
202 Some(Operation::Ee) if children.is_empty() => Some(Pair(Vec::new(), Vec::new())),
203 Some(_) => None,
204 None if children.is_empty() => Some(One(vec![symbol])),
205 None => None,
206 }
207 }
208
209 fn parse_object(&mut self, input: &str) -> Result<Self::InternalValue, Self::ParseError> {
210 Ok(self.parse_string(input))
211 }
212
213 fn to_external(&self, value: &Self::InternalValue) -> Self::Value {
214 let resolve = |values: &[Symbol]| {
215 values
216 .iter()
217 .map(|&symbol| self.signature.resolve(symbol).to_owned())
218 .collect()
219 };
220 match value {
221 TagStringValue::String(words) => TagStringValue::String(resolve(words)),
222 TagStringValue::Pair(left, right) => {
223 TagStringValue::Pair(resolve(left), resolve(right))
224 }
225 }
226 }
227
228 fn visualize(&self, value: &Self::Value) -> VisualRepresentation {
229 self.display_codec.encode(value)
230 }
231}
232
233#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
235pub enum TagSpan {
236 String(Span),
238 Pair(Span, Span),
240}
241
242impl fmt::Display for TagSpan {
243 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
244 match self {
245 Self::String(span) => write!(f, "{span}"),
246 Self::Pair(left, right) => write!(
247 f,
248 "[{}-{}, {}-{}]",
249 left.start, left.end, right.start, right.end
250 ),
251 }
252 }
253}
254
255impl TagSpan {
256 fn valid(self, n: usize) -> bool {
257 match self {
258 Self::String(span) => span.start <= span.end && span.end <= n,
259 Self::Pair(left, right) => {
260 left.start <= left.end
261 && left.end <= right.start
262 && right.start <= right.end
263 && right.end <= n
264 }
265 }
266 }
267}
268
269#[derive(Clone, Debug)]
271pub struct TagStringDecompositionAutomaton {
272 operations: FxHashMap<Symbol, Operation>,
273 words: Vec<Symbol>,
274 positions_by_word: FxHashMap<Symbol, Vec<usize>>,
275}
276
277impl TagStringDecompositionAutomaton {
278 fn new(operations: FxHashMap<Symbol, Operation>, words: Vec<Symbol>) -> Self {
279 let mut positions_by_word = FxHashMap::default();
280 for (position, &word) in words.iter().enumerate() {
281 positions_by_word
282 .entry(word)
283 .or_insert_with(Vec::new)
284 .push(position);
285 }
286 Self {
287 operations,
288 words,
289 positions_by_word,
290 }
291 }
292
293 pub fn len(&self) -> usize {
295 self.words.len()
296 }
297
298 pub fn is_empty(&self) -> bool {
300 self.words.is_empty()
301 }
302
303 fn operation(&self, symbol: Symbol) -> Option<Operation> {
304 self.operations.get(&symbol).copied()
305 }
306
307 fn symbol_for(&self, operation: Operation) -> Symbol {
308 self.operations
309 .iter()
310 .find_map(|(&symbol, &candidate)| (candidate == operation).then_some(symbol))
311 .expect("all TAG operations are registered")
312 }
313
314 fn step_operation(
315 &self,
316 operation: Operation,
317 children: &[TagSpan],
318 out: &mut dyn FnMut(TagSpan),
319 ) {
320 use TagSpan::{Pair, String as One};
321 match (operation, children) {
322 (Operation::Conc11, [One(left), One(right)]) if left.end == right.start => {
323 out(One(Span::new(left.start, right.end)));
324 }
325 (Operation::Conc12, [One(first), Pair(left, right)]) if first.end == left.start => {
326 out(Pair(Span::new(first.start, left.end), *right));
327 }
328 (Operation::Conc21, [Pair(left, right), One(second)]) if right.end == second.start => {
329 out(Pair(*left, Span::new(right.start, second.end)));
330 }
331 (Operation::Wrap21, [Pair(left, right), One(middle)])
332 if left.end == middle.start && middle.end == right.start =>
333 {
334 out(One(Span::new(left.start, right.end)));
335 }
336 (
337 Operation::Wrap22,
338 [
339 Pair(first_left, first_right),
340 Pair(second_left, second_right),
341 ],
342 ) if first_left.end == second_left.start && second_right.end == first_right.start => {
343 out(Pair(
344 Span::new(first_left.start, second_left.end),
345 Span::new(second_right.start, first_right.end),
346 ));
347 }
348 (Operation::E, []) => {
349 for i in 0..=self.len() {
350 out(One(Span::new(i, i)));
351 }
352 }
353 (Operation::Ee, []) => {
354 for i in 0..=self.len() {
355 for j in i..=self.len() {
356 out(Pair(Span::new(i, i), Span::new(j, j)));
357 }
358 }
359 }
360 _ => {}
361 }
362 }
363}
364
365impl BottomUpTa for TagStringDecompositionAutomaton {
366 type State = TagSpan;
367
368 fn step(&self, symbol: Symbol, children: &[TagSpan], out: &mut dyn FnMut(TagSpan)) {
369 if let Some(operation) = self.operation(symbol) {
370 self.step_operation(operation, children, &mut |state| {
371 if state.valid(self.len()) {
372 out(state);
373 }
374 });
375 } else if children.is_empty()
376 && let Some(positions) = self.positions_by_word.get(&symbol)
377 {
378 for &position in positions {
379 out(TagSpan::String(Span::new(position, position + 1)));
380 }
381 }
382 }
383
384 fn is_accepting(&self, state: &TagSpan) -> bool {
385 *state == TagSpan::String(Span::new(0, self.len()))
386 }
387}
388
389impl StateUniverse for TagStringDecompositionAutomaton {
390 fn all_states(&self, out: &mut dyn FnMut(TagSpan)) {
391 let n = self.len();
392 for start in 0..=n {
393 for end in start..=n {
394 out(TagSpan::String(Span::new(start, end)));
395 }
396 }
397 for i in 0..=n {
398 for j in i..=n {
399 for k in j..=n {
400 for l in k..=n {
401 out(TagSpan::Pair(Span::new(i, j), Span::new(k, l)));
402 }
403 }
404 }
405 }
406 }
407}
408
409impl TopDownTa for TagStringDecompositionAutomaton {
410 fn step_topdown(&self, parent: &TagSpan, out: &mut dyn FnMut(Symbol, &[TagSpan])) {
411 use TagSpan::{Pair, String as One};
412 if !parent.valid(self.len()) {
413 return;
414 }
415
416 match *parent {
417 One(span) => {
418 if span.len() == 1 {
419 out(self.words[span.start], &[]);
420 }
421 if span.is_empty() {
422 out(self.symbol_for(Operation::E), &[]);
423 }
424 for split in span.start..=span.end {
425 let children = [
426 One(Span::new(span.start, split)),
427 One(Span::new(split, span.end)),
428 ];
429 out(self.symbol_for(Operation::Conc11), &children);
430 }
431 for start in span.start..=span.end {
432 for end in start..=span.end {
433 let children = [
434 Pair(Span::new(span.start, start), Span::new(end, span.end)),
435 One(Span::new(start, end)),
436 ];
437 out(self.symbol_for(Operation::Wrap21), &children);
438 }
439 }
440 }
441 Pair(left, right) => {
442 if left.is_empty() && right.is_empty() {
443 out(self.symbol_for(Operation::Ee), &[]);
444 }
445 for split in left.start..=left.end {
446 let children = [
447 One(Span::new(left.start, split)),
448 Pair(Span::new(split, left.end), right),
449 ];
450 out(self.symbol_for(Operation::Conc12), &children);
451 }
452 for split in right.start..=right.end {
453 let children = [
454 Pair(left, Span::new(right.start, split)),
455 One(Span::new(split, right.end)),
456 ];
457 out(self.symbol_for(Operation::Conc21), &children);
458 }
459 for split_left in left.start..=left.end {
460 for split_right in right.start..=right.end {
461 let children = [
462 Pair(
463 Span::new(left.start, split_left),
464 Span::new(split_right, right.end),
465 ),
466 Pair(
467 Span::new(split_left, left.end),
468 Span::new(right.start, split_right),
469 ),
470 ];
471 out(self.symbol_for(Operation::Wrap22), &children);
472 }
473 }
474 }
475 }
476 }
477
478 fn initial_states(&self, out: &mut dyn FnMut(TagSpan)) {
479 out(TagSpan::String(Span::new(0, self.len())));
480 }
481}
482
483impl CondensedTa for TagStringDecompositionAutomaton {
484 fn condensed_rules(&self, out: &mut dyn FnMut(&[TagSpan], &SymbolSet, TagSpan)) {
485 self.all_states(&mut |state| {
486 self.step_topdown(&state, &mut |symbol, children| {
487 let mut symbols = SymbolSet::new();
488 symbols.insert(symbol);
489 out(children, &symbols, state);
490 });
491 });
492 }
493
494 fn condensed_nullary_rules(&self, out: &mut dyn FnMut(&SymbolSet, TagSpan)) {
495 for (position, &word) in self.words.iter().enumerate() {
496 let mut symbols = SymbolSet::new();
497 symbols.insert(word);
498 out(&symbols, TagSpan::String(Span::new(position, position + 1)));
499 }
500 let mut e = SymbolSet::new();
501 e.insert(self.symbol_for(Operation::E));
502 for i in 0..=self.len() {
503 out(&e, TagSpan::String(Span::new(i, i)));
504 }
505 let mut ee = SymbolSet::new();
506 ee.insert(self.symbol_for(Operation::Ee));
507 for i in 0..=self.len() {
508 for j in i..=self.len() {
509 out(&ee, TagSpan::Pair(Span::new(i, i), Span::new(j, j)));
510 }
511 }
512 }
513
514 fn condensed_rules_by_child(
515 &self,
516 position: usize,
517 state: &TagSpan,
518 out: &mut dyn FnMut(&[TagSpan], &SymbolSet, TagSpan),
519 ) {
520 if position > 1 {
521 return;
522 }
523 self.all_states(&mut |parent| {
524 self.step_topdown(&parent, &mut |symbol, children| {
525 if children.get(position) == Some(state) {
526 let mut symbols = SymbolSet::new();
527 symbols.insert(symbol);
528 out(children, &symbols, parent);
529 }
530 });
531 });
532 }
533}
534
535impl IndexedBottomUpTa for TagStringDecompositionAutomaton {
536 fn step_partial(
537 &self,
538 symbol: Symbol,
539 position: usize,
540 state_at_position: &TagSpan,
541 out: &mut dyn FnMut(&[TagSpan], TagSpan),
542 ) {
543 let Some(operation) = self.operation(symbol) else {
544 return;
545 };
546 if !matches!(
547 operation,
548 Operation::Conc11
549 | Operation::Conc12
550 | Operation::Conc21
551 | Operation::Wrap21
552 | Operation::Wrap22
553 ) || position > 1
554 {
555 return;
556 }
557
558 self.all_states(&mut |partner| {
559 let children = if position == 0 {
560 [*state_at_position, partner]
561 } else {
562 [partner, *state_at_position]
563 };
564 self.step_operation(operation, &children, &mut |parent| {
565 if parent.valid(self.len()) {
566 out(&children, parent);
567 }
568 });
569 });
570 }
571}
572
573#[cfg(test)]
574mod tests {
575 use super::*;
576
577 #[test]
578 fn displays_string_and_pair_spans_compactly() {
579 assert_eq!(TagSpan::String(Span::new(2, 5)).to_string(), "[2-5]");
580 assert_eq!(
581 TagSpan::Pair(Span::new(2, 3), Span::new(3, 4)).to_string(),
582 "[2-3, 3-4]"
583 );
584 }
585
586 #[test]
587 fn evaluates_all_operations() {
588 let mut algebra = TagStringAlgebra::new();
589 let a = TagStringValue::String(vec![algebra.intern_word("a")]);
590 let b = TagStringValue::String(vec![algebra.intern_word("b")]);
591 let pair = TagStringValue::Pair(
592 vec![algebra.intern_word("l")],
593 vec![algebra.intern_word("r")],
594 );
595
596 let eval = |name, children: &[TagStringValue<Symbol>]| {
597 algebra.evaluate(algebra.operation_symbol(name).unwrap(), children)
598 };
599 assert!(
600 matches!(eval(CONC11, &[a.clone(), b.clone()]), Some(TagStringValue::String(v)) if v.len() == 2)
601 );
602 assert!(
603 matches!(eval(CONC12, &[a.clone(), pair.clone()]), Some(TagStringValue::Pair(l, r)) if l.len() == 2 && r.len() == 1)
604 );
605 assert!(
606 matches!(eval(CONC21, &[pair.clone(), b.clone()]), Some(TagStringValue::Pair(l, r)) if l.len() == 1 && r.len() == 2)
607 );
608 assert!(
609 matches!(eval(WRAP21, &[pair.clone(), b.clone()]), Some(TagStringValue::String(v)) if v.len() == 3)
610 );
611 assert!(
612 matches!(eval(WRAP22, &[pair.clone(), pair.clone()]), Some(TagStringValue::Pair(l, r)) if l.len() == 2 && r.len() == 2)
613 );
614 }
615
616 #[test]
617 fn decomposition_accepts_empty_and_repeated_words() {
618 let mut algebra = TagStringAlgebra::new();
619 let value = algebra.parse_string("a a");
620 let decomp = algebra.decompose(value).unwrap();
621 let a = algebra.signature().get("a").unwrap();
622 let mut states = Vec::new();
623 decomp.step(a, &[], &mut |state| states.push(state));
624 assert_eq!(states.len(), 2);
625
626 let empty_value = algebra.parse_string("");
627 let empty = algebra.decompose(empty_value).unwrap();
628 let e = algebra.operation_symbol(TAG_E).unwrap();
629 let mut empty_states = Vec::new();
630 empty.step(e, &[], &mut |state| empty_states.push(state));
631 assert!(empty_states.iter().any(|state| empty.is_accepting(state)));
632 }
633}