soma.cell

Quadratic equations — discriminant and the two real roots

For ax² + bx + c = 0 the discriminant D = b² − 4ac decides the root count: D > 0 two real roots, D == 0 one repeated, D < 0 none real. Vieta's relations cross-check: roots sum to −b/a and multiply to c/a.

A Soma program from the math part of the verified corpus: 54 lines, cells Quadratic, QuadraticTests. It passes soma check with soma 3.2.4.

How it is built

The cell Quadratic declares 3 signals in its face: discriminant(a: Float, b: Float, c: Float) -> Float, roots(a: Float, b: Float, c: Float) -> List and run() -> Map. Handlers: discriminant (line 19), roots (line 23) and run (line 32).

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

Generated from soma describe on this file.

The source

quadratic.cell

// ============================================================================
// Quadratic equations — discriminant and the two real roots
// ============================================================================
//
// For ax² + bx + c = 0 the discriminant D = b² − 4ac decides the root count:
// D > 0 two real roots, D == 0 one repeated, D < 0 none real. Vieta's
// relations cross-check: roots sum to −b/a and multiply to c/a.
//
//   soma run quadratic.cell run
// ============================================================================

cell Quadratic {
    face {
        signal discriminant(a: Float, b: Float, c: Float) -> Float
        signal roots(a: Float, b: Float, c: Float) -> List
        signal run() -> Map
    }

    on discriminant(a: Float, b: Float, c: Float) {
        return b * b - 4.0 * a * c
    }

    on roots(a: Float, b: Float, c: Float) {
        let d = discriminant(a, b, c)
        if d < 0.0 { return [] }              // no real roots
        let sq = sqrt(d)
        let r1 = (0 - b + sq) / (2.0 * a)
        let r2 = (0 - b - sq) / (2.0 * a)
        return [r1, r2]
    }

    on run() {
        // x^2 - 5x + 6 = 0 -> roots 3 and 2
        let r = roots(1.0, 0 - 5.0, 6.0)
        return map("discriminant", discriminant(1.0, 0 - 5.0, 6.0), "roots", r)
    }
}

cell test QuadraticTests {
    rules {
        // x^2 - 5x + 6: D = 25 - 24 = 1
        assert discriminant(1.0, 0 - 5.0, 6.0) == 1.0
        // roots are 3 and 2
        assert abs(roots(1.0, 0 - 5.0, 6.0)[0] - 3.0) < 0.0000001
        assert abs(roots(1.0, 0 - 5.0, 6.0)[1] - 2.0) < 0.0000001
        // Vieta: sum of roots = -b/a = 5
        assert abs(sum(roots(1.0, 0 - 5.0, 6.0)) - 5.0) < 0.0000001
        // Vieta: product of roots = c/a = 6
        assert abs(product(roots(1.0, 0 - 5.0, 6.0)) - 6.0) < 0.0000001
        // negative discriminant -> no real roots
        assert len(roots(1.0, 0.0, 1.0)) == 0
    }
}

What the toolchain says

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

$ soma check quadratic.cell
✓ All checks passed.
$ soma test quadratic.cell
test QuadraticTests ...
  ✓ assert discriminant(1.0, 0 - 5.0, 6.0) == 1.0
  ✓ assert abs(roots(1.0, 0 - 5.0, 6.0)[0] - 3.0) < 0.0000001
  ✓ assert abs(roots(1.0, 0 - 5.0, 6.0)[1] - 2.0) < 0.0000001
  ✓ assert abs(sum(roots(1.0, 0 - 5.0, 6.0)) - 5.0) < 0.0000001
  ✓ assert abs(product(roots(1.0, 0 - 5.0, 6.0)) - 6.0) < 0.0000001
  ✓ assert len(roots(1.0, 0.0, 1.0)) == 0

6 tests: 6 passed, 0 failed
$ soma verify quadratic.cell
Verifying quadratic.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 quadratic.cell run
{"discriminant": 1.0, "roots": [3.0, 2.0]}

Builtins used

abs, len, map, product, sqrt, sum

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