Levenshtein edit distance — classic 2D dynamic programming
Demonstrates: a DP table as a List of rows (each a List), nested loops over i,j, the insert/delete/substitute min recurrence, and min() over a list.
A Soma program from the algorithms part of the verified corpus: 53 lines, cells EditDistance, EditDistanceTests. It passes soma check with soma 3.2.4.
How it is built
The cell EditDistance declares 1 signal in its face: distance(a: String, b: String) -> Int. Handlers: distance (line 13).
The file also holds 1 test cell (EditDistanceTests) with 6 assertions, run by soma test.
The source
edit_distance.cell
// Levenshtein edit distance — classic 2D dynamic programming.
// Demonstrates: a DP table as a List of rows (each a List), nested loops over
// i,j, the insert/delete/substitute min recurrence, and min() over a list.
//
// soma run examples/corpus/algorithms/edit_distance.cell distance kitten sitting
// soma test examples/corpus/algorithms/edit_distance.cell
cell EditDistance {
face {
signal distance(a: String, b: String) -> Int
}
on distance(a: String, b: String) {
let ca = split(a, "")
let cb = split(b, "")
let n = len(ca)
let m = len(cb)
// dp[i][j] = edit distance between a[0..i) and b[0..j)
let dp = list()
for i in range(0, n + 1) {
let row = list()
for j in range(0, m + 1) { row = push(row, 0) }
dp = push(dp, row)
}
for i in range(0, n + 1) { dp[i][0] = i }
for j in range(0, m + 1) { dp[0][j] = j }
for i in range(1, n + 1) {
for j in range(1, m + 1) {
let cost = if ca[i - 1] == cb[j - 1] { 0 } else { 1 }
dp[i][j] = min(list(
dp[i - 1][j] + 1, // deletion
dp[i][j - 1] + 1, // insertion
dp[i - 1][j - 1] + cost // substitution
))
}
}
return dp[n][m]
}
}
cell test EditDistanceTests {
rules {
assert distance("kitten", "sitting") == 3
assert distance("flaw", "lawn") == 2
assert distance("", "abc") == 3
assert distance("abc", "") == 3
assert distance("same", "same") == 0
assert distance("a", "b") == 1
}
}What the toolchain says
$ soma check edit_distance.cell
✓ All checks passed.$ soma test edit_distance.cell
test EditDistanceTests ...
✓ assert distance("kitten", "sitting") == 3
✓ assert distance("flaw", "lawn") == 2
✓ assert distance("", "abc") == 3
✓ assert distance("abc", "") == 3
✓ assert distance("same", "same") == 0
✓ assert distance("a", "b") == 1
6 tests: 6 passed, 0 failed$ soma verify edit_distance.cell
Verifying edit_distance.cell...
No state machine in this program: nothing to prove beyond `soma check` (invariants and lifecycles are what verify proves).
VERIFY OK (vacuous — no state machine)$ soma run edit_distance.cell distance kitten sitting
3