soma.cell

Vector operations — dot product, norm, cosine similarity

Vectors are plain lists. dot() zips two lists and sums the pairwise products; norm is sqrt of the self-dot; cosine similarity normalizes the dot by the product of the norms. Reductions (sum) and zip do the work.

A Soma program from the math part of the verified corpus: 56 lines, cells VectorOps, VectorTests. It passes soma check with soma 3.2.4.

How it is built

The cell VectorOps declares 4 signals in its face: dot(a: List, b: List) -> Float, norm(a: List) -> Float, cosine(a: List, b: List) -> Float and run() -> Map. Handlers: dot (line 20), norm (line 25), cosine (line 29) and run (line 33).

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

Generated from soma describe on this file.

The source

vector_ops.cell

// ============================================================================
// Vector operations — dot product, norm, cosine similarity
// ============================================================================
//
// Vectors are plain lists. dot() zips two lists and sums the pairwise
// products; norm is sqrt of the self-dot; cosine similarity normalizes the
// dot by the product of the norms. Reductions (sum) and zip do the work.
//
//   soma run vector_ops.cell run
// ============================================================================

cell VectorOps {
    face {
        signal dot(a: List, b: List) -> Float
        signal norm(a: List) -> Float
        signal cosine(a: List, b: List) -> Float
        signal run() -> Map
    }

    on dot(a: List, b: List) {
        let prods = zip(a, b) |> map(p => p.left * p.right)
        return sum(prods)
    }

    on norm(a: List) {
        return sqrt(dot(a, a))
    }

    on cosine(a: List, b: List) {
        return dot(a, b) / (norm(a) * norm(b))
    }

    on run() {
        let u = [3, 4]
        let v = [4, 3]
        return map(
            "dot", dot(u, v),
            "norm_u", norm(u),
            "cosine", cosine(u, v)
        )
    }
}

cell test VectorTests {
    rules {
        // 3*4 + 4*3 = 24
        assert dot([3, 4], [4, 3]) == 24
        // |(3,4)| = 5
        assert norm([3, 4]) == 5.0
        // orthogonal vectors have zero dot, cosine 0
        assert dot([1, 0], [0, 1]) == 0
        // identical unit-ish vectors have cosine 1
        assert abs(cosine([1, 2], [1, 2]) - 1.0) < 0.0000001
    }
}

What the toolchain says

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

$ soma check vector_ops.cell
✓ All checks passed.
$ soma test vector_ops.cell
test VectorTests ...
  ✓ assert dot([3, 4], [4, 3]) == 24
  ✓ assert norm([3, 4]) == 5.0
  ✓ assert dot([1, 0], [0, 1]) == 0
  ✓ assert abs(cosine([1, 2], [1, 2]) - 1.0) < 0.0000001

4 tests: 4 passed, 0 failed
$ soma verify vector_ops.cell
Verifying vector_ops.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 vector_ops.cell run
{"dot": 24, "norm_u": 5.0, "cosine": 0.96}

Builtins used

abs, map, sqrt, sum, zip

Source file: /corpus/math/vector_ops.cell · examples/corpus/math/vector_ops.cell