Carl is a tool that runs Monte Carlo simulations on deterministic spreadsheet models for sensitivity analysis.
Point it at a spreadsheet you already have, declare which cells are uncertain and which cells you care about, and it resamples the inputs, recalculates the model, and streams out every iteration. The model itself is never rewritten — the spreadsheet stays the source of truth, and Carl drives it.
The spreadsheet engine currently uses LibreOffice, but I would love to add more options or switch to something cleaner in the future.
- Install LibreOffice
- Clone and install this repo:
pip install -e . - Ensure that your Python environment has the
uno.pyandunohelper.pyin it'sPATH
If LibreOffice is not at /usr/lib/libreoffice, set LIBREOFFICE_PATH in a .env file
(see .env.template) to point at the install.
A config file declares the uncertain inputs and the outputs to capture. Ranges are
Sheet!A1 style, and an output may be a single cell or a block.
name = "MC Example"
[[assumptions]]
name = "Assumption 1"
range = "Sheet1!A1"
distribution.name = "uniform"
distribution.kwargs = {low = 1, high = 5}
[[assumptions]]
name = "Assumption 2"
range = "Sheet1!A2"
distribution.name = "poisson"
distribution.kwargs = {lam = 2}
[[outputs]]
name = "Output 1"
range = "Sheet1!A3:C3"distribution.name is dispatched directly to NumPy's random Generator, so any
distribution NumPy exposes works — normal, uniform, poisson, lognormal,
triangular, binomial, and the rest. distribution.kwargs is passed through
verbatim, so parameter names are NumPy's own.
carl simulate [OPTIONS] MODEL_PATH
-c, --config-path TEXT config file (default: default.toml)
-n, --nreps INTEGER iterations to run (default: 1000)
-f, --output-format TEXT json or csv (default: json)
Run the example simulation:
carl simulate -c ./examples/example.toml ./examples/example.ods -n 1000Every iteration is emitted alongside the assumptions that produced it, so results stay auditable — an outlier can always be traced back to the draw that caused it.
For analysis in a spreadsheet or dataframe, ask for CSV. Output cells are flattened into
name.row.col columns:
carl simulate -c ./examples/example.toml ./examples/example.ods -n 1000 -f csv > results.csvOr pipe the JSON straight into a terminal histogram (I know this is ugly):
carl simulate -c ./examples/example.toml ./examples/example.ods -n 1000 \
| jq -r '.[].outputs."Output 1"[0][0]' \
| awk 'BEGIN {print "Output 1"} {print $0}' \
| p9 plot -f - 'ggplot(df, aes(x="Output 1")) + geom_histogram()' \
| timg -See LICENSE.
