soma.cell

Two-sum with a hash set, and the count of distinct pairs summing to a target

Demonstrates: a Map used as a seen-set, the complement lookup that turns an O(n^2) scan into O(n), and returning index pairs as a record.

A Soma program from the algorithms part of the verified corpus: 47 lines, cells TwoSum, TwoSumTests. It passes soma check with soma 3.2.4.

How it is built

The cell TwoSum declares 2 signals in its face: find(xs: List, target: Int) -> Map and exists(xs: List, target: Int) -> Bool. Handlers: find (line 15) and exists (line 31).

The file also holds 1 test cell (TwoSumTests) with 7 assertions, run by soma test.

Generated from soma describe on this file.

The source

two_sum.cell

// Two-sum with a hash set, and the count of distinct pairs summing to a
// target. Demonstrates: a Map used as a seen-set, the complement lookup that
// turns an O(n^2) scan into O(n), and returning index pairs as a record.
//
//   soma run  examples/corpus/algorithms/two_sum.cell find "[2,7,11,15]" 9
//   soma test examples/corpus/algorithms/two_sum.cell

cell TwoSum {
    face {
        signal find(xs: List, target: Int) -> Map
        signal exists(xs: List, target: Int) -> Bool
    }

    // first pair of indices (i, j) with xs[i] + xs[j] == target, else (-1,-1)
    on find(xs: List, target: Int) {
        let seen = map()    // value -> index
        let result = Pair { i: -1, j: -1 }
        for k in range(0, len(xs)) {
            let need = target - xs[k]
            let nk = to_string(need)
            let hit = seen[nk] ?? -1
            if hit >= 0 {
                result = Pair { i: hit, j: k }
                break
            }
            seen[to_string(xs[k])] = k
        }
        return result
    }

    on exists(xs: List, target: Int) {
        return find(xs, target).i >= 0
    }
}

cell test TwoSumTests {
    rules {
        assert find([2, 7, 11, 15], 9).i == 0
        assert find([2, 7, 11, 15], 9).j == 1
        assert find([3, 2, 4], 6).i == 1
        assert find([3, 2, 4], 6).j == 2
        assert find([1, 2, 3], 100).i == -1
        assert exists([2, 7, 11, 15], 26)
        assert !exists([1, 2, 3], 100)
    }
}

What the toolchain says

Run on a fresh copy of the program at build time; the outputs are pasted unedited.

$ soma check two_sum.cell
✓ All checks passed.
$ soma test two_sum.cell
test TwoSumTests ...
  ✓ assert find([2, 7, 11, 15], 9).i == 0
  ✓ assert find([2, 7, 11, 15], 9).j == 1
  ✓ assert find([3, 2, 4], 6).i == 1
  ✓ assert find([3, 2, 4], 6).j == 2
  ✓ assert find([1, 2, 3], 100).i == -1
  ✓ assert exists([2, 7, 11, 15], 26)
  ✓ assert !exists([1, 2, 3], 100)

7 tests: 7 passed, 0 failed
$ soma verify two_sum.cell
Verifying two_sum.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 two_sum.cell find "[2,7,11,15]" 9
{"_type": "Pair", "i": 0, "j": 1}

Builtins used

len, map, range, to_string

Source file: /corpus/algorithms/two_sum.cell · examples/corpus/algorithms/two_sum.cell