Date: 2025-11-22 Discovery: Deep investigation revealed is_valid_trace definition permits duplicate pairs Impact: Blocks NoDup-based proofs, requires alternative approaches
The is_valid_trace definition in Distance.v does NOT prevent duplicate pairs from appearing in traces.
Root Cause: compatible_pairs(p, p) = true
Definition compatible_pairs (p1 p2 : nat * nat) : bool :=
let '(i1, j1) := p1 in
let '(i2, j2) := p2 in
if (i1 =? i2) && (j1 =? j2) then true (* same pair - ALLOWS duplicates! *)
else if (i1 =? i2) || (j1 =? j2) then false
else if i1 <? i2 then j1 <? j2 else j2 <? j1.
Consequence: is_valid_trace_aux checks forallb (compatible_pairs head) tail, which passes even if head appears again in tail.
A trace like T = [(1,2), (3,4), (1,2), (5,6)] would pass is_valid_trace:
(1,2) checks compatibility with [(3,4), (1,2), (5,6)]
compatible_pairs (1,2) (3,4) = true ✓compatible_pairs (1,2) (1,2) = true ✓ (allows duplicate!)compatible_pairs (1,2) (5,6) = true ✓Attempted to prove:
Lemma is_valid_trace_aux_NoDup :
forall T, is_valid_trace_aux T = true -> NoDup T.
Result: UNPROVABLE with current definition (lines 1972-2037 in Distance.v)
The proof reaches a point where we need to derive a contradiction from:
(i,j) ∈ tailcompatible_pairs (i,j) (i,j) = trueBut this is consistent! No contradiction exists.
Direct impact:
is_valid_trace_aux_NoDup - UNPROVABLE (fundamental blocker)touched_in_A_NoDup - BLOCKED (depends on #1)touched_in_B_NoDup - BLOCKED (depends on #1)Indirect impact:
4. incl_length_correct - Uses NoDup hypotheses
5. trace_composition_cost_bound Part 2 - Original approach used NoDup + incl
The triangle inequality proof (lev_distance_triangle_inequality) uses:
distance_equals_min_trace_cost (optimal trace exists)trace_composition_cost_bound (composition cost bound)Part 2 of trace_composition_cost_bound was planned to use:
touched_in_A A C comp ⊆ touched_in_A A B T1 (proven)
touched_in_B A C comp ⊆ touched_in_B B C T2 (proven)
+ NoDup on touched lists
→ length bounds
→ deletion/insertion cost arithmetic with 2|B| slack
Without NoDup: The incl → length implication fails.
Change:
Definition is_valid_trace (A B : list Char) (T : Trace A B) : bool :=
(forallb (valid_pair (length A) (length B)) T) &&
is_valid_trace_aux T &&
nodupb pair_eq_dec T. (* ADD THIS *)
Pros:
Cons:
Estimated effort:
Approach: Prove as lemma rather than definition:
Lemma dp_trace_has_nodup :
forall A B T,
extracted_from_dp_matrix A B T ->
is_valid_trace A B T = true ->
NoDup T.
Pros:
Cons:
Estimated effort: 5-10 hours (DP formalization)
Insight: Part 2 arithmetic might not actually NEED NoDup!
Alternative bound for incl without NoDup:
Lemma incl_length_with_multiplicity :
forall {A} (l1 l2 : list A),
incl l1 l2 ->
length l1 <= length l2 * length l2.
Or use direct counting:
Lemma touched_length_bound_by_trace :
forall A B T,
length (touched_in_A A B T) <= length T.
(Already proven at line 1930!)
New Part 2 approach:
length (touched_in_A A C comp) <= length comp (proven)length comp <= length T1 * length T2 (composition size bound)Pros:
Cons:
Estimated effort: 2-4 hours (exploratory arithmetic)
Approach: Accept current admits, document clearly, continue with other work
Pros:
Cons:
For production/completeness: Option 1 (strengthen definition)
For exploration/research: Option 3 (alternative counting)
Week 1: Try Option 3 (2-4 hours)
Week 2: If Option 3 fails, implement Option 1
Week 3+: Complete DP extraction (Option 2 bonus)
Commits: Fundamental discovery documented in code (lines 2017-2046)
Admits remaining:
Triangle inequality: Provable modulo 4-5 well-documented admits
This discovery exemplifies the scientific method in formal verification:
Documentation of failed proof attempts is as valuable as successful proofs: it guides later proof sessions and prevents repeated dead ends.
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 |