soma.cell

Monte Carlo — estimate pi by dart-throwing

Throw random points into the unit square; the fraction landing inside the quarter circle (x²+y² ≤ 1) approaches pi/4. random() is the time-seeded PRNG — flagged nondeterministic for `soma replay`, so the estimate varies run-to-run. The test asserts only that the estimate is in a loose band.

A Soma program from the math part of the verified corpus: 44 lines, cells MonteCarloPi, MonteCarloTests. It passes soma check with soma 3.2.4.

How it is built

The cell MonteCarloPi declares 2 signals in its face: estimate(samples: Int) -> Float and run() -> Map. Handlers: estimate (line 19) and run (line 29).

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

Generated from soma describe on this file.

The source

monte_carlo_pi.cell

// ============================================================================
// Monte Carlo — estimate pi by dart-throwing
// ============================================================================
//
// Throw random points into the unit square; the fraction landing inside the
// quarter circle (x²+y² ≤ 1) approaches pi/4. random() is the time-seeded
// PRNG — flagged nondeterministic for `soma replay`, so the estimate varies
// run-to-run. The test asserts only that the estimate is in a loose band.
//
//   soma run monte_carlo_pi.cell run
// ============================================================================

cell MonteCarloPi {
    face {
        signal estimate(samples: Int) -> Float
        signal run() -> Map
    }

    on estimate(samples: Int) {
        let inside = 0
        for i in range(0, samples) {
            let x = random()
            let y = random()
            if x * x + y * y <= 1.0 { inside = inside + 1 }
        }
        return 4.0 * to_float(inside) / to_float(samples)
    }

    on run() {
        let pi = estimate(100000)
        return map("estimate", pi, "error", abs(pi - 3.141592653589793))
    }
}

cell test MonteCarloTests {
    rules {
        // 50k darts lands within a generous band of pi (PRNG is seeded by time)
        assert abs(estimate(50000) - 3.14159) < 0.1
        // the estimate is always a sane positive number below 4
        assert estimate(2000) > 2.5
        assert estimate(2000) < 4.0
    }
}

What the toolchain says

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

$ soma check monte_carlo_pi.cell
✓ All checks passed.
$ soma test monte_carlo_pi.cell
test MonteCarloTests ...
  ✓ assert abs(estimate(50000) - 3.14159) < 0.1
  ✓ assert estimate(2000) > 2.5
  ✓ assert estimate(2000) < 4.0

3 tests: 3 passed, 0 failed
$ soma verify monte_carlo_pi.cell
Verifying monte_carlo_pi.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 monte_carlo_pi.cell run
{"estimate": 3.14116, "error": 0.00043265358979294177}

Builtins used

abs, map, random, range, to_float

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