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.
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
$ 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}