Source
tests/purrc/app_montecarlo_test.cpp
1
// Copyright (c) 2026 BigBrain LLC. MIT-licensed (see LICENSE).2
// Original work; see ACKNOWLEDGMENTS.md for the open-source ideas we build upon.3
// Sophisticated multi-module system-level test: a small "Monte Carlo4
// simulation" app that only passes if `random`, `math`, `statistics`, and `io`5
// all cooperate end to end (purrc + the C++ backend + the runtime + the linked6
// stdlib).7
//8
// The program:9
// - estimates pi by sampling points in the unit square and counting those in10
// the quarter unit circle (random.random + math.sqrt),11
// - asserts reproducibility by running the same seeded estimate twice and12
// comparing for equality,13
// - summarizes seeded gaussian draws with statistics.mean/stdev (math.round14
// keeps the printed values stable),15
// - exercises random.randint / random.uniform as well.16
//17
// Everything is seeded, so the printed numbers are reproducible byte-for-byte.18
// The expected stdout below was verified by compiling and running the program19
// three times (twice from one build, once from a fresh compile) and confirming20
// identical output before hardcoding.22
#include "e2e_harness.hpp"25
TEST(SystemApps, MonteCarlo) {26
e2e::expect_e2e("app_montecarlo", R"PURR(import io27
import math28
import random29
import statistics31
# Monte Carlo estimate of pi: sample points in the unit square and count32
# the fraction that land inside the quarter unit circle. Seeded RNG makes33
# the estimate fully reproducible, so the printed result is deterministic.34
fn estimate_pi(seed, n) {35
random.seed(seed)36
let inside = 037
let i = 038
for i in range(0, n) {39
let x = random.random()40
let y = random.random()41
if math.sqrt(x * x + y * y) <= 1.0 {42
inside = inside + 143
}44
}45
return 4.0 * inside / n46
}48
let n = 5000050
# (1) Deterministic pi estimate (rounded so the printed value is stable).51
let pi_hat = estimate_pi(2024, n)52
let pi_rounded = math.round(pi_hat * 1000.0) / 1000.054
# (2) Reproducibility: same seed twice => byte-identical estimate.55
let pi_again = estimate_pi(2024, n)56
let reproducible = pi_hat == pi_again58
# (3) Summarize 10 seeded gauss draws with `statistics`.59
let samples = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]60
random.seed(99)61
let k = 062
for k in range(0,10) {63
samples[k] = random.gauss(100.0, 15.0)64
}65
let mu = math.round(statistics.mean(samples) * 100.0) / 100.066
let sd = math.round(statistics.stdev(samples) * 100.0) / 100.068
# (4) randint / uniform sanity, also seeded.69
random.seed(7)70
let d1 = random.randint(1, 6)71
let d2 = random.randint(1, 6)72
let u = math.round(random.uniform(0.0, 1.0) * 1000.0) / 1000.074
io.print("pi ~=", pi_rounded)75
io.print("reproducible:", reproducible)76
io.print("abs err <= 0.05:", math.fabs(pi_hat -3.14159265) <= 0.05)77
io.print("gauss mean:", mu, "stdev:", sd)78
io.print("dice:", d1, d2, "uniform:", u)79
)PURR",80
"pi ~= 3.141\n"81
"reproducible: True\n"82
"abs err <= 0.05: True\n"83
"gauss mean: 94.14 stdev: 14.84\n"84
"dice: 4 1 uniform: 0.117\n");85
}