Date: 2025-11-11 Status: ✅ COMPLETE (Policy parameter threaded through all transition functions) Tests: ✅ 491/491 passing
Successfully integrated substitution policy parameter into the lazy (parameterized) Levenshtein automaton implementation. All transition functions now accept a generic P: SubstitutionPolicy parameter, enabling future support for restricted substitutions while maintaining zero-cost abstraction for the default Unrestricted policy.
characteristic_vector ✅File: src/transducer/transition.rs:30-52
Changes:
P: SubstitutionPolicy parameterRationale: Initially attempted to integrate policy into characteristic vector, but after testing, determined that the characteristic vector should remain an exact match indicator. The policy check should be applied in the transition logic itself when computing substitution costs.
transition_state ✅File: src/transducer/transition.rs:536-579
Changes:
pub fn transition_state<U: CharUnit, P: SubstitutionPolicy>(
state: &State,
policy: P, // ← Added parameter
dict_unit: U,
query: &[U],
max_distance: usize,
algorithm: Algorithm,
prefix_mode: bool,
) -> Option<State>
transition_state_pooled ✅File: src/transducer/transition.rs:609-668
Changes:
P: SubstitutionPolicy generic parameterpolicy: P parameter (3rd parameter position)Updated 5 files to pass Unrestricted policy to transition functions:
| File | Line | Status |
|---|---|---|
src/dictionary/dawg_query.rs | 187 | ✅ Fixed |
src/transducer/automaton_zipper.rs | 185 | ✅ Fixed |
src/transducer/query.rs | 163 | ✅ Fixed |
src/transducer/ordered_query.rs | 222 | ✅ Fixed |
src/transducer/value_filtered_query.rs | 209, 389 | ✅ Fixed (2 sites) |
Pattern Applied:
// Added import
use super::{..., Unrestricted};
// Updated call
transition_state_pooled(
&state,
&mut pool,
Unrestricted, // ← Added parameter
label,
&query,
max_distance,
algorithm,
prefix_mode,
)
File: src/transducer/transition.rs:689-772
Changes:
use crate::transducer::Unrestricted; importtest_characteristic_vector to pass Unrestricted policytest_transition_state to pass Unrestricted policy$ cargo build
Compiling liblevenshtein v0.6.0
Finished `dev` profile in 0.69s
✅ Success (6 warnings, 0 errors)
$ cargo test --lib
test result: ok. 491 passed; 0 failed; 0 ignored
✅ All tests passing
Key Tests Verified:
test_characteristic_vector - Exact match semantics preservedtest_transition_state - State transitions work with policytest_single_substitution - Substitution logic intacttest_deletion - Deletion operations worktest_candidate_iterator - End-to-end query functionalityInitial Approach: Apply policy in characteristic_vector to mark positions as matching if policy allows substitution.
Problem: Tests failed - characteristic vector was returning [true, true, true] instead of [true, false, false].
Root Cause: The characteristic vector represents exact matches only. It's used by transition functions to determine if a character advancement costs 0 errors. Policy-based "matches" are actually substitutions (cost = 1 error).
Solution: Keep characteristic vector as exact match only. Policy check will be applied in transition logic when considering substitution operations.
Code Change:
// Final implementation
for (i, item) in buffer.iter_mut().enumerate().take(len) {
let query_idx = offset + i;
*item = query_idx < query.len() && query[query_idx] == dict_unit;
// No policy check here - it belongs in transition logic
}
Status: Deferred to Phase 7
Rationale: The policy parameter is now threaded through, but we haven't yet verified zero-cost abstraction via:
cargo asm)This will be Phase 7's focus.
Current Status: No performance regression expected because:
Unrestricted is a zero-sized type (0 bytes)is_allowed() returns constant true - compiler optimizes this awayUnrestricted (monomorphization to original code)Verification Needed: Phase 7 will benchmark to confirm zero overhead.
Transducer API to accept policy parameter with defaultUniversalAutomatonaccepts() method to use policyUnrestricted policy usageAdding generic SubstitutionPolicy parameter with Unrestricted default will enable restricted substitutions with zero overhead for the unrestricted case.
✅ Compilation: Code compiles with policy parameter ✅ Tests: All 491 tests pass - no regression ⏳ Performance: Not yet verified (Phase 7) ⏳ Assembly: Not yet inspected (Phase 7)
Policy parameter successfully threaded through lazy automaton. No functional regressions detected. Zero-cost abstraction hypothesis remains to be verified in Phase 7.
src/transducer/transition.rs (3 functions, 1 test module)src/transducer/query.rssrc/transducer/ordered_query.rssrc/transducer/value_filtered_query.rssrc/dictionary/dawg_query.rssrc/transducer/automaton_zipper.rsTotal: ~3.25 hours for Phase 3 core work
Characteristic Vector Semantics: Represents exact matches only, not policy-allowed matches. Policy checks belong in transition logic, not match detection.
Test-Driven Development: Test failures immediately revealed the semantic error in characteristic_vector implementation.
Zero-Sized Types: The Unrestricted policy compiles to 0 bytes, making it ideal for zero-cost abstraction.
Mechanical Changes: Once the pattern was established, fixing all call sites was straightforward and mechanical.
docs/development/RESTRICTED_SUBSTITUTIONS_PLAN.mddocs/migration/LAZY_EAGER_TERMINOLOGY.mddocs/optimization/parameterized-vs-universal-2025-11-11/COMPARISON_REPORT.mdCan 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 |