1 Describe the possibilities
In this model, a 30% chance of rain leaves a 70% chance of sun. Write if 30% and Probl follows both possibilities, keeping track of how likely each one is.
Write down what might happen. Probl works out how likely each outcome is. Use familiar variables, functions and loops to explore game odds, compare decisions and make forecasts.
Try an example and change the assumptions. Everything runs in your browser, with no installation.
Or install the command line with Cargo
cargo install probl-cli --locked
let total ~ 2d6report total >= 10 as "Rolling 10 or more"
enumeratedRolling 10 or more 16.67%
What’s the chance of rolling 10 or more with two six-sided dice? 2d6 adds the dice together; report asks for the odds. The answer: 16.67%. Try changing 10 to another number.
How it works
Give Probl the choices and their chances. It follows the possible outcomes, combines paths that lead to the same situation, and answers the questions you ask.
In this model, a 30% chance of rain leaves a 70% chance of sun. Write if 30% and Probl follows both possibilities, keeping track of how likely each one is.
let weather = if 30% { "rain" } else { "sun" }report weather
"rain"30%"sun"70%Flip a coin to step left or right. Left then right brings you back to the start, just like right then left. Probl combines those two paths: together, they give a 50% chance of being back at zero.
When only your current position matters, Probl can skip keeping every route separately. That makes many models much smaller.
var pos = 0repeat 3 { pos += if 50% { 1 } else { -1 } }report pos
Use report to ask what you want to know: the chance of rain, the odds of winning, or how long you might wait. Probl brings the possibilities together in one result.
enumeratedweather sun 70.00% · rain 30.00%
Games
Describe dice rolls, card draws and the rules of each turn. Probl follows the game and calculates the chances of each result.
# Risk: 10 attacking armies against 8 defenders, fought to the end. enumeratevar attackers = 10var defenders = 8while attackers > 1 and defenders > 0 { # The attacker rolls up to three dice but must leave one army at home; # the defender rolls up to two. roll(n, d6) gives the dice sorted high to low. let attack ~ roll(min(3, attackers - 1), d6) let defend ~ roll(min(2, defenders), d6) # Highest against highest, second against second. Ties go to the defender. for i in 0..<min(attack.len(), defend.len()) { if attack[i] > defend[i] { defenders -= 1 } else { attackers -= 1 } }}# A full round has 56 × 21 distinct dice outcomes. But once it's over, the# dice are never read again, so the only state left is the two army counts:# the worlds merge back into a handful after every round.report defenders == 0 as "attacker conquers"report attackers - 1 as "armies left to move in"
enumeratedattacker conquers 64.64%armies left to move in mean 3.05 · sd 2.78 · 5% 0 · median 3 · 95% 8 · 0 █▁▂▃▃▃▃▂▂▁ 9
In craps, your first roll can win, lose, or set a target. If it sets a target, keep rolling: hit that total again to win, or roll a seven to lose. Probl works out the overall chance of winning: 49.29%.
# Craps, pass line bet: what's the chance of winning?let come_out ~ 2d6 # one world per totalvar win = falseif come_out in [7, 11] { win = true} else if come_out not in [2, 3, 12] { loop { # keep rolling for the point let r ~ 2d6 if r == come_out { win = true; break } if r == 7 { break } }}report win
enumeratedwin 49.29%
Forecasting
How might revenue grow after a launch? Let growth and customer losses vary, run the model many times, and see both the likely outcomes and the wider range of possibilities.
90% of runs 50% median
3% to 7% models positive growth, with 90% of draws falling between 3% and 7%.normal_range(-8%, 0%) allows for losses, with 90% of draws falling between −8% and 0%.report … by month shows how the outlook changes each month. Wider bands in the chart mean a wider range of possible results.sample · 50,000 runs · seed 11MRR ≥ $100k after 18 months 33.3% ± 0.2%
let price = 49 # $ per customer per monthlet churn ~ 3% to 7% # share of customers who leave each month: uncertain, but fixedvar market ~ one_of([Boom: 20%, Steady: 60%, Slump: 20%])var signups ~ 60 to 150 # new customers per month at launchvar customers = 0for month in 1..18 { let new ~ poisson(signups) let lost ~ binomial(customers, churn) customers += new - lost report customers * price by month as "MRR ($)" market = next_month(market) let growth ~ match market { # month-on-month growth in sign-ups Boom => 8% to 20% Steady => 1% to 6% Slump => normal_range(-8%, 0%) # growth can be negative: say which shape you mean } signups *= 1 + growth}report customers * price >= 100_000 as "MRR ≥ $100k after 18 months"
# A condition affects 1% of the population.let sick ~ bernoulli(1%)# Sensitivity is 95%; the false-positive rate is 8%.observe true from bernoulli(if sick { 95% } else { 8% })report sick
enumerated · evidence 8.87%sick 10.71%
Evidence
Use observe to tell Probl what you have learned. It rules out outcomes that no longer fit and adjusts the chances of the remaining possibilities.
Suppose a condition affects 1% of people. A test detects it 95% of the time, but also gives a positive result for 8% of people without it. After a positive test, what is the chance of having the condition? In this model, 10.71%.
You can also bring your own data into a model from CSV, JSON or text files.
Beyond dice and coins
An arrival time could be anywhere within half an hour. A success rate might be somewhere between zero and one. Probl can work with these ranges too, and calculate results directly for supported models.
let arrival ~ uniform(0, 30)observe arrival > 10let wait = max(arrival - 15, 0)report wait as "wait (minutes)"report wait > 10 as "waiting more than 10 minutes"
enumerated · evidence 66.67%wait (minutes) mean 5.62 · sd 4.96 · 5% 0.00 · median 5.00 · 95% 14.00waiting more than 10 minutes 25.00%
You know an arrival will be after minute 10. How long will you wait beyond minute 15? There is a 25% chance of no extra wait.
let rate ~ beta(2, 2)observe 3 from binomial(5, rate)report ratereport rate > 50%
enumerated · evidence 21.43%rate mean 0.56 · sd 0.16 · 5% 0.29 · median 0.56 · 95% 0.81rate > 50% 63.67%
Start with an uncertain success rate, then tell Probl that three of five attempts succeeded. It updates the rate and reports the chance that it is above 50%.
Interpreting results
By default, Probl follows the possible outcomes and combines their probabilities. This is called enumeration. For larger models, you can choose sampling: many random runs that estimate the answer. Probl does not switch automatically.
Reports show how the answer was calculated and flag any unresolved probability. Probabilities use floating-point numbers; fractions marked ≈ are approximate.
enumerated · evidence 8.87% sample · 50,000 runs · seed 11
Keep the same model, data, Probl version, date and random seed to repeat a successful run. This makes it easier to share a result and check what changes when you adjust an assumption.
Tests compare results with known answers and, for some models, a separate implementation. Other checks compare calculations with repeated simulations. The testing guide explains what is covered and what remains to check.
If two days each have an independent 30% chance of a storm, the chance of both being stormy is 9%. Asking about the same storm twice still gives 30%. Use = to define a chance you can draw from, and ~ to draw one outcome and reuse it.
let storm = bernoulli(30%)report storm and storm as "two independent storms"let happened ~ stormreport happened and happened as "the same storm twice"
enumeratedtwo independent storms 9.00%the same storm twice 30.00%
Get started
Start with an example, change a few values and run it again. The editor offers suggestions and help as you type. Share a link so someone else can try your model.
Open the playgroundInstall Rust (1.99 or later), then run this in your terminal:
cargo install probl-cli --locked
Save the following as first-roll.probl:
let total ~ 2d6report total >= 10 as "Rolling 10 or more"
In the folder where you saved the file, run:
probl run first-roll.probl
You’ll see a 16.67% chance of rolling 10 or more. Change the number in the file and run it again.
Examples
Examples cover games, forecasting, calendars, decisions, monitoring and risk. Each includes assumptions and expected results, and opens in the playground.
simulate, a balancing sweep
report … by
a to b estimates, regime switching, a fan chart over months
observe … from, learning a rate, then forecasting with it
today, weekends, explicit holidays and deadline probability
Probl is early-stage and its syntax is still evolving. Some models are too large to calculate fully, and not every kind of calculation is supported. The language guide introduces the available features; the reference explains their limits.
Probl draws on ideas from Squiggle, AnyDice and WebPPL. Source code is available on GitHub under MIT or Apache-2.0, without warranty.