EB#

A domain-specific language for Monte Carlo simulation and stochastic modeling.

EB is being developed as part of a PhD research project.

Why EB?#

Clarity

Write models that read like their mathematical specification. Guard expressions and lineitems make conditional logic and time-series relationships explicit.

Correctness

The type system and domain-specific constructs catch errors early. Observations are collected automatically at the right granularity.

Performance

Compile to native binary for production. Use the REPL for exploration. Run millions of iterations efficiently.

Features#

  • Lineitems: Time-varying expressions re-evaluated each period with automatic history

  • Observations: Data collection at period, iteration, run, or simulation level

  • Guard expressions: Pattern matching for clean conditional logic

  • Scenarios: Named parameter sets for comparative analysis

  • Native compilation: Generate C code for high-performance execution

Example#

The run() {I, R} statement executes I iterations across R runs. A lineitem (li) is an expression evaluated once per iteration.

# Estimate Pi using Monte Carlo

niter := 100_000
nrun  :=     100

li x := :randu(-1.0, 1.0)
li y := :randu(-1.0, 1.0)
li inside := | x^2 + y^2 <= 1.0 -> inside + 1
             | _                -> inside

obs_r estimate := 4.0 * inside / niter

run() {niter, nrun}
:print(:boxplot(estimate))
:print("estimate of Pi, mean of observations:", :mean(estimate))

Output:

[min=3.1265, Q1=3.1370, med=3.1411, Q3=3.1447, max=3.1535, n=100]
estimate of Pi, mean of observations: 3.14092

Comparison with Python#

The same Monte Carlo Pi estimation in Python:

import random
import statistics

niter = 100_000
nrun = 100

estimates = []

for run in range(nrun):
    inside = 0
    for i in range(niter):
        x = random.uniform(-1.0, 1.0)
        y = random.uniform(-1.0, 1.0)
        if x**2 + y**2 <= 1.0:
            inside += 1
    estimate = 4.0 * inside / niter
    estimates.append(estimate)

sorted_est = sorted(estimates)
n = len(sorted_est)
min_v = sorted_est[0]
q1 = sorted_est[int(n * 0.25)]
med = sorted_est[int(n * 0.50)]
q3 = sorted_est[int(n * 0.75)]
max_v = sorted_est[-1]

print(f"[min={min_v:.4f}, Q1={q1:.4f}, med={med:.4f}, Q3={q3:.4f}, max={max_v:.4f}, n={n}]")
print("estimate of Pi:", statistics.mean(estimates))

Timing: 5.8s (Python) vs 1.5s (EB)

% time python3 pi.py
python3 pi.py  5.74s user 0.02s system 99% cpu 5.775 total

% time ./pi
./pi  1.52s user 0.00s system 99% cpu 1.530 total