The CompressedSuffixAutomaton is a proof-of-concept implementation demonstrating that compression techniques can be applied to suffix automata. However, it has known defects and is not ready for production use.
Problem: Building suffix automaton from multiple texts doesn't work correctly.
Symptoms:
from_texts(vec!["text1", "text2"]) may not find substrings from "text2"Root Cause: The online construction algorithm for generalized suffix automaton is not correctly implemented. The issue is likely in how we handle state cloning and suffix link updates when transitioning between texts.
What Needs Fixing:
SuffixAutomaton implementation more carefullyextend() method's handling of state cloningTest Case to Fix:
let sa = CompressedSuffixAutomaton::from_texts(vec![
"Pack my box with five dozen liquor jugs",
"The quick brown fox jumps",
]);
assert!(sa.contains("box")); // Currently fails!
assert!(sa.contains("quick")); // Currently fails!
Problem: Integration with Levenshtein automaton via Transducer is untested and may not work.
Symptoms:
What Needs Testing:
let sa = CompressedSuffixAutomaton::from_text("testing");
let transducer = Transducer::new(sa, Algorithm::Standard);
// Should find "testing" with distance 1
let results: Vec<_> = transducer.query("testng", 1).collect();
assert!(!results.is_empty()); // Currently fails?
What Needs Fixing:
Problem: Only achieving ~26% memory savings instead of theoretical ~50%.
Current: ~52 bytes/state Original: ~48 bytes/state (with HashMap) Expected: ~20-30 bytes/state
Root Cause: Vec overhead is 24 bytes per Vec, which dominates the savings from smaller integer types.
Possible Solutions:
Trade-offs:
Replace Vec<(u8, u32)> edges with BASE/CHECK arrays:
struct TrueCompressedSuffixAutomaton {
base: Vec<i32>, // BASE[state] + byte = next_state
check: Vec<i32>, // CHECK[next_state] == state (validation)
suffix_link: Vec<u32>,
max_length: Vec<u16>,
flags: Vec<u8>,
}
Benefits:
Challenges:
Implement DictionaryFromTerms trait:
#[cfg(feature = "serialization")]
impl crate::serialization::DictionaryFromTerms for CompressedSuffixAutomaton {
fn from_terms<I: IntoIterator<Item = String>>(terms: I) -> Self {
CompressedSuffixAutomaton::from_texts(terms)
}
}
Blocked By: Need to fix generalized suffix automaton first.
Once generalized SA is fixed, benchmark:
// benches/suffix_automaton_comparison.rs
fn bench_compressed_vs_original(c: &mut Criterion) {
let texts = load_large_corpus(); // 100+ texts
// Construction time
// Memory usage
// Query performance (exact and fuzzy)
}
Add position metadata like original SuffixAutomaton:
struct CompressedSuffixAutomatonInner {
// ... existing fields
positions: HashMap<usize, Vec<(usize, usize)>>, // (text_id, position)
}
Use Case: Finding where in the original texts a substring occurs.
src/dictionary/suffix_automaton.rsdocs/SUFFIX_AUTOMATON_DESIGN.mdKEEP but clearly marked as experimental:
Total: 16-31 hours to make production-ready
Last Updated: 2025-01-XX
Status: Experimental / Incomplete
Recommendation: Use SuffixAutomaton for production
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |