Date: 2025-11-13 Status: Debugging with concrete trace
The relevant subword function creates:
// For position i (1-indexed), n=1:
// start = i - n
// end = min(|w|, i + n)
// Characters from position start to end (1-indexed, inclusive)
Input[0] = 'b', position i=1:
s_1("ab", 1) = characters from position (1-1=0) to min(2, 1+1=2) = positions 0 to 2Input[1] = 'a', position i=2:
s_1("ab", 2) = characters from position (2-1=1) to min(2, 2+1=3) = positions 1 to 2State = {I+0#0_usual}
Bit vector: β('b', "$ab") = [0, 0, 1]
Position I+0#0_usual (offset=0, errors=0):
Check match at index n+offset = 1+0 = 1:
Standard successors (from successors_i_type_standard):
Let me review the standard successor logic...
Actually, looking at the existing code, the standard successors for I-type check bit_vector[n+offset]:
Standard successors for I+0#0:
Transposition check (Usual state):
The condition !bit_vector.is_match(next_match_index) should be checking if b[1] = 0.
Looking at Mitankin's Definition 7:
δ^D,t_e(i#e, b) = δ^D_e(i#e, b) ∪ {(i+1)#(e+1)_t} if b[1] = 0 ∧ e < n
This means: "Enter transposition state if b[1] = 0 (no match at position 1)".
In our case:
But next_match_index = 2, and bit_vector[2] = 1, so the condition !bit_vector.is_match(2) = false.
The bit vector indexing in thesis vs. implementation:
In Mitankin's thesis, b[k] means "the k-th bit in the characteristic vector" (0-indexed into the vector itself).
In our implementation:
bit_vector[n+offset+k] to get what corresponds to thesis notation b[k]For position I+0#0:
b[0] in thesis = bit_vector[n+offset] = bit_vector[1+0] = bit_vector[1]b[1] in thesis = bit_vector[n+offset+1] = bit_vector[1+0+1] = bit_vector[2]So the mapping is correct! Let me reconsider...
Wait, I need to understand what b[1] represents semantically.
b[k] SemanticsLooking at the relevant subword for position i=1, n=1:
The subword represents word positions relative to the current position:
Now, for position i#e:
ib[0] checks if input character matches word[i]b[1] checks if input character matches word[i+1]For position 1#0 (I+0#0):
b[0] checks if 'b' matches word[1] = 'a' → NOb[1] checks if 'b' matches word[2] = 'b' → YES!So b[1] = 1, not b[1] = 0.
According to Definition 7, we enter transposition when b[1] = 0. Since b[1] = 1, we should NOT enter transposition here.
This is correct! The transposition check is working as intended for this case.
Since we don't enter transposition from I+0#0, the successors are just the standard ones:
New state = {I+0#1, I+1#1, I+(-1)#1}
Bit vector: β('a', "ab") = [1, 0]
Let's trace each position:
Position I+0#1 (offset=0, errors=1):
Ah! The bit vector length depends on the subword, which changes based on input position.
For input position i=2, the subword is "ab" (length 2), so the bit vector has length 2.
For position I+0#1:
Standard successors from I+0#1:
Position I+1#1 (offset=1, errors=1):
This means the match check should be guarded. But wait, the bit vector should have sufficient length...
I think the problem is that the bit vector length depends on the subword length, which varies based on input position and word boundaries.
Let me re-read how the subword is constructed and verify the indexing...
Actually, looking at line 222-223 in position.rs:
if next_match_index < bit_vector.len()
&& !bit_vector.is_match(next_match_index)
The bounds check is there! So if the index is out of bounds, we don't enter transposition.
Let me reconsider the problem from a different angle.
Maybe the issue is that I'm misunderstanding what "entering transposition state" means.
Looking at Definition 7 again:
The transposition operation swaps two adjacent characters. The state machine:
But this doesn't match my current implementation! In my implementation:
Wait, that's wrong. Let me recompute:
So the offset doesn't change! That seems suspicious.
Let me look at the I^ε conversion formula from the thesis...
From the thesis:
I^ε({i#e}) = {I+(i-1)#e}
So for position i#e, we store it as I+(i-1)#e. This means:
Wait, that's for the ε (standard) variant. Let me check if transposition uses a different conversion...
Actually, looking at the implementation, I see that for I-type positions:
But the thesis Definition 15 says I^ε({i#e}) = {I+(i-1)#e}, which suggests stored_offset = i-1 for the parameter-free (ε) variant.
I think there's confusion between the different notations. Let me look at the implementation of new_i to understand what offset represents...
I need to deeply understand the position representation and bit vector indexing before I can fix the transposition logic. The issue is complex and involves:
This requires consulting the thesis more carefully and possibly adding comprehensive debug logging to trace through a simple example.
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 |