Skip to content

[wip/levenshtein] Prove DP/recursive equivalence bridge#25

Merged
joom merged 3 commits into
bloomberg:mainfrom
CharlesCNorton:sproof/levenshtein-bridge
Feb 26, 2026
Merged

[wip/levenshtein] Prove DP/recursive equivalence bridge#25
joom merged 3 commits into
bloomberg:mainfrom
CharlesCNorton:sproof/levenshtein-bridge

Conversation

@CharlesCNorton
Copy link
Copy Markdown
Contributor

@CharlesCNorton CharlesCNorton commented Feb 21, 2026

Summary

This PR completes the missing bridge between the dynamic-programming Levenshtein model and Crane's intrinsic recursive model.

It adds a new proof file tests/wip/levenshtein/BridgeDP.v and refactors tests/wip/levenshtein/Levenshtein.v to expose reusable recurrence lemmas used by the bridge.

Why this matters

Before this PR, we had:

  • a recursive intrinsic implementation/proof in Levenshtein.v
  • a loop-structured DP model in progress

but no completed theorem showing they compute the same value for the same inputs.

This PR closes that gap with:

  • lev_dp_string_eq_levenshtein_computed

What changed

1) New file: tests/wip/levenshtein/BridgeDP.v

Adds a full DP formalization and bridge proof:

  • DP model definitions:
    • dp_min, inner_loop, process_row, outer_result_run
    • lev_dp_list, lev_dp_string
  • Row/cache invariants and loop correctness lemmas:
    • row_values, row_last
    • inner_loop_cont_correct
    • process_row_correct_nonempty
    • outer_result_run_correct
  • Orientation/reversal machinery:
    • chain_append_right
    • chain_add_last_source
    • chain_strip_last_source
    • chain_update_last_source
    • rev_string, chain_rev_string
    • levenshtein_computed_rev_string
    • lev_spec_list_rev
  • Main bridge theorem:
    • lev_dp_string_eq_levenshtein_computed

2) Refactor: tests/wip/levenshtein/Levenshtein.v

Adds reusable lemmas and reduces repeated proof patterns:

  • new helper lemmas:
    • levenshtein_computed_of_chain
    • levenshtein_computed_nil_l
    • levenshtein_computed_nil_r
    • levenshtein_computed_cons_neq
  • mismatch upper-bound lemmas now rewrite through levenshtein_computed_cons_neq and finish with lia instead of re-deriving min3 branch details each time
  • updates fragile Nat.* references to PeanoNat.Nat.* where needed for current Rocq compatibility

Dependency chain (project-level)

Within Crane, this PR establishes:

  • DP model (BridgeDP.v) -> recursive model (Levenshtein.v)

In the broader 4-file story discussed during development:

  • levenshtein-vst/levenshtein.v + levenshtein-vst/verif_levenshtein.v (VST side, separate toolchain)
  • tests/wip/levenshtein/BridgeDP.v + tests/wip/levenshtein/Levenshtein.v (this PR)

So this PR contributes the Crane-side bridge artifact and its required recurrence refactor.

Verification

Ran locally (Rocq toolchain used by Crane tests):

  • coqc -Q /mnt/d/crane/theories Crane -Q /mnt/d/crane/tests/wip/levenshtein '' /mnt/d/crane/tests/wip/levenshtein/Levenshtein.v
  • coqc -Q /mnt/d/crane/theories Crane -Q /mnt/d/crane/tests/wip/levenshtein '' /mnt/d/crane/tests/wip/levenshtein/BridgeDP.v

Both compile successfully.

Proof hygiene:

  • no Admitted
  • no Axiom

Diff summary

  • tests/wip/levenshtein/BridgeDP.v: new file (+912)
  • tests/wip/levenshtein/Levenshtein.v: +564 / -179

@CharlesCNorton
Copy link
Copy Markdown
Contributor Author

Companion artifact (separate toolchain) is now published at:

This contains the VST/CompCert-side files (levenshtein.v, �erif_levenshtein.v, levenshtein.c, _CoqProject) and build instructions. The split keeps this Crane PR focused on the Rocq/Dune bridge proof files.

@joom
Copy link
Copy Markdown
Member

joom commented Feb 25, 2026

I'm trying to keep the tests in a specific format: one Rocq file, one .t.cpp file, and generated .h and .cpp files. This PR breaks this format, so I'm not sure what the right thing to do is. One possible solution is to have a separate levenshtein_dp test (only with the dynamic programming version of the function). Another solution is to add the dynamic programming version (and all the proofs) directly in the Levenshtein.v file. My worry about that is that the file already does a lot, but I guess the second solution is the better option? What do you think?

Add a new bridge proof file tests/wip/levenshtein/BridgeDP.v that formalizes a loop-structured Wagner-Fischer DP model and proves it computes the same value as levenshtein_computed.

BridgeDP adds DP model definitions, cache/row invariants, reverse-orientation machinery, and the final theorem lev_dp_string_eq_levenshtein_computed.

Refactor Levenshtein.v by adding reusable lemmas (levenshtein_computed_of_chain, nil_l/nil_r, cons_neq), simplifying mismatch upper-bound lemmas via cons_neq + lia, and updating Nat lemma references to PeanoNat.Nat where needed for current Rocq compatibility.

Result is axiom-free (no Admitted/Axiom) and closes the DP↔recursive equivalence in the Crane Rocq test suite.
Merge the DP bridge (Wagner-Fischer model, row specification,
reversal argument, and lev_dp_string_eq_levenshtein_computed)
into Levenshtein.v after End Levenshtein, keeping one .v file
per test folder. Delete BridgeDP.v.
@CharlesCNorton CharlesCNorton force-pushed the sproof/levenshtein-bridge branch from aa3bef0 to 21ac706 Compare February 26, 2026 11:54
@joom joom merged commit 5ec7857 into bloomberg:main Feb 26, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants