Prove termination of diff algorithm implementation - #37
Draft
ninioArtillero wants to merge 20 commits into
Draft
Conversation
The manhattan distance from a node towards the algorithm's end point (lena, lenb) is used as termination metric for `addsnake`. Phantom parameters for both input lengths are introduced to provide them as arguments to the metric. The diagonal predicate `DiagPred` is a refinement type alias encoding the condition of an equality predicate (such as `canDiag`) to enter the recursive call inside `addsnake`. This allows Liquid Haskell to know that both coordinates are smaller than its corresponding input length, those fulfilling `manhattanDistance` preconditions. `dstep` is extended to provide the required phantom parameters and is temporarily ignored because proving node coordinates in a wave front are within bounds (`manhatanDistance` preconditions) requires discarting out-of-bounds nodes. This is implemented as an optimization in a following commit.
A `_wfDistanceToGoal` function is defined to be used as termination metric for `ses`. In this commit, `dstep` is specified and checked to reduce it from input to output. The wave front diagonal condition is changed to look at the head of the node list instead of the diagonal edit distance parameter, and its nodes are specified to be within bounds. Indeed, now that wave fronts are trimmed down to be within bounds, we can no longer guarantee that the first node's diagonal matches the edit distance. The `stepAndMerge` specification is strengthen to preserve this new variant of wave front diagonal invariant: With the current optimization of `dstep`, wave fronts don't necessarily grow, but the 2-step specing is preserved.
The implementation of `ses` changes from a `dropWhile` driven search for the algorithm's end point in a lazy stream composed of all wave front nodes, to the explicit recursion of a wave-front wise search for such end point. This change was designed to allow a termination proof using Liquid Haskell: by inspecting each wave front separately, instead of all concatenated together in an infinite stream, we can define a wave front metric as its minimum distance to the endpoint and show it is reduced by the recursive calls (to `dstep`). Performance-wise, we get a small optimization of the benchmark of ~12%
Contributor
…eason#28) The optimization introduced in `dstep` (narrowing the wave front to only within bound nodes) solves the problem this additional equations addressed in seereason@33bf8bc They are removed to avoid unnecessary complexity.
ninioArtillero
force-pushed
the
xg/ses-termination
branch
from
August 5, 2026 22:46
9928375 to
e5cb8c3
Compare
Co-authored-by: Facundo Domínguez <facundominguez@gmail.com>
ninioArtillero
force-pushed
the
xg/ses-termination
branch
from
August 6, 2026 21:48
e5cb8c3 to
34f28ed
Compare
The introduced benchmark makes the improvement of the `dstep` refactoring (dropping out-of-bounds nodes) more noticeable.
A definition less, plus upstream has an optimization for `const` in ucsd-progsys/liquidhaskell#2732 that could turn out to be useful (currently is makes no difference because lemmas are not being composed).
ninioArtillero
force-pushed
the
xg/ses-termination
branch
from
August 7, 2026 19:54
e7d2434 to
2f99dfb
Compare
Comment on lines
+414
to
+418
| -- The next node being on the right border means all | ||
| -- previous nodes cannot compete to the endpoint, because their | ||
| -- children require more steps to cross the next node's diagonal. | ||
| -- HACK: However, we keep @prev@'s vertical child node to preserve | ||
| -- the '_wfDiags' invariant at a negligible performance penalty. |
Contributor
There was a problem hiding this comment.
Suggested change
| -- The next node being on the right border means all | |
| -- previous nodes cannot compete to the endpoint, because their | |
| -- children require more steps to cross the next node's diagonal. | |
| -- HACK: However, we keep @prev@'s vertical child node to preserve | |
| -- the '_wfDiags' invariant at a negligible performance penalty. | |
| -- The next node being on the right border means that | |
| -- 'furthestReaching' would produce a node outside the grid, | |
| -- However, we keep @prev@'s vertical child node to preserve | |
| -- the '_wfDiags' invariant at a negligible performance penalty. | |
| -- See issue BLAH for alternatives. |
We need issue BLAH. Or perhaps a note in the code discussing the balance.
Co-authored-by: Facundo Domínguez <facundominguez@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
All commits build independenlty and can be read in sequence.