Open in new tab

Probly is a Python-like mini-language for probabilistic estimation. It's based on Starlark and implemented in Go.

Start with Example 1

Probly syntax

You may use any Starlark syntax. There are only the following differences to Starlark:

  • A variable may follow a probability distribution, in addition to usual types like numbers or dictionaries
  • The Starlark math module is imported by default, so you can directly use it e.g. math.sqrt(2). Probly also has a built-in sum function not available in Starlark.

This page will show you the probability distributions of all the numeric (scalar or distribution) global variables in your program (except those starting with an underscore). The values are taken at the end of the program's execution.

Probability distributions

Name to
p10 to p90
pm
plus/minus
td
times/divide
Quantiles Notes
Normal mean sd 2
LogNormal mu sigma 2 Alternatively: mean, sd
Beta alpha beta
PERT min mode max [lambd] Like the triangular, but smoother (Wikipedia)
Uniform a b 2 a need not be less than b
LogUniform a b 2 a need not be less than b
Bernoulli p
Binomial n p
Discrete x_1 p_1 x_2 p_2 ... Generic discrete distribution over any finite set of values

math

These mathematical functions and constants are available in the math module:

  • pow(x, y) - Returns x raised to the power of y
  • exp(x)
  • sqrt(x)
  • log(x, [base]) - Natural logarithm by default if base is not specified
  • e
  • pi
  • Ceil, floor, and sign manipulation:
    • ceil(x)
    • floor(x)
    • fabs(x) - Returns the absolute value of x as float
    • copysign(x, y) - Returns a value with the magnitude of x and the sign of y
  • mod(x, y) - Returns x modulo y
  • remainder(x, y)
  • round(x) - Returns the nearest integer, rounding half away from zero
  • Trigonometry (in radians unless otherwise specified):
    • acos(x)
    • asin(x)
    • atan(x)
    • atan2(y, x) - Returns atan(y / x). The result is between -pi and pi
    • cos(x)
    • sin(x)
    • tan(x)
    • degrees(x) - Converts angle x from radians to degrees
    • radians(x) - Converts angle x from degrees to radians
    • acosh(x)
    • asinh(x)
    • atanh(x)
    • cosh(x)
    • sinh(x)
    • tanh(x)
  • hypot(x, y) - Returns the Euclidean norm, sqrt(x^2 + y^2); the distance from the origin to (x, y)
  • gamma(x) - Returns the Gamma function at x

Starlark syntax

This code provides an example of the syntax of Starlark:

# Define a number
number = 18

# Define a list
numbers = [1, 2, 3, 4, 5]

# List comprehension
halves = [n / 2 for n in numbers]

# Define a function
def is_even(n):
    """Return True if n is even."""
    return n % 2 == 0

# Define a dictionary
people = {
    "Alice": 22,
    "Bob": 40,
    "Charlie": 55,
    "Dave": 14,
}

names = ", ".join(people.keys())  # Alice, Bob, Charlie, Dave

# Modify a variable in a loop
sum_even_ages = 0
for age in people.values():
    if is_even(age):
        sum_even_ages += age

# Append to a list in a loop
over_30_names = []
for name, age in people.items():
    if age > 30:
        over_30_names.append(name)

If you've ever used Python, this should look very familiar. In fact, the code above is also valid Python code. Still, this short example shows most of the language. Starlark is a very small language that implements a limited subset of Python.

For our purposes, one notable difference to Python is that the exponentiation operator ** is not supported. You have to use math.pow.

You can also look at the Starlark language specification.

Speed

Though not designed for speed, Probly is fast enough for practical purposes: around 10 milliseconds for 3,000 samples, for most examples on this page. This is due to being implemented in Go.

The time taken to return results on this page is spent overwhelmingly in web application code, not in Probly evaluation.

Interestingly, Probly is still slower than Python code that uses entirely numpy array operations, which are very well optimised. This should only begin to matter at very large scales, or if latency is critical.

Limitations

It's not currently possible to obtain and manipulate properties of a distribution within an Probly program, like so:

x = Normal(1 to 10)
y = x.std()  # Not possible

Supporting this would require some fundamental changes to the implementation of Probly, which is currently quite simple. I haven't prioritised this yet because I'm unsure how desirable the feature is.

Prior work

The to binary operator was inspired by Squiggle.

Example Factory Investment

We are considering building an additional factory. We will sell more units, but the price may fall. What's the return on investment?

The additional quantity due to our factory has an effect on the price (i.e. the market is a monopoly or oligopoly). This is modeled with a linear demand curve.

This simple model assumes competitors do not react to our decision.

Distribution details

roi

Mean 0.042 3
Std. dev. 0.030 9
Variance 0.000 957
Quantile
0.05 -0.010 2
0.25 0.021 8
0.50 0.043 5
0.75 0.062 3
0.95 0.092 9

profit_with_factory

Mean 34.9
Std. dev. 7.60
Variance 57.8
Quantile
0.05 19.6
0.25 29.7
0.50 37.5
0.75 41.4
0.95 43.1

profit_baseline

Mean 22.8
Std. dev. 0
Variance 0
Quantile
0.05 22.8
0.25 22.8
0.50 22.8
0.75 22.8
0.95 22.8

unit_cost

Mean 10.1
Std. dev. 0
Variance 0
Quantile
0.05 10.1
0.25 10.1
0.50 10.1
0.75 10.1
0.95 10.1

p_with_factory

Mean 11.6
Std. dev. 0.317
Variance 0.100
Quantile
0.05 10.9
0.25 11.3
0.50 11.7
0.75 11.8
0.95 11.9

demand_slope

Mean -0.037 1
Std. dev. 0.026 4
Variance 0.000 696
Quantile
0.05 -0.090 1
0.25 -0.055 3
0.50 -0.028 2
0.75 -0.014 4
0.95 -0.008 81

factory_cost

Mean 317
Std. dev. 100
Variance 10 100
Quantile
0.05 179
0.25 246
0.50 300
0.75 374
0.95 504

factory_capacity

Mean 12.0
Std. dev. 0
Variance 0
Quantile
0.05 12.0
0.25 12.0
0.50 12.0
0.75 12.0
0.95 12.0

p_baseline

Mean 12.0
Std. dev. 0
Variance 0
Quantile
0.05 12.0
0.25 12.0
0.50 12.0
0.75 12.0
0.95 12.0

q_baseline

Mean 12.0
Std. dev. 0
Variance 0
Quantile
0.05 12.0
0.25 12.0
0.50 12.0
0.75 12.0
0.95 12.0

Simulation data

CSV

Download CSV

Preview

q_baseline p_baseline factory_capacity factory_cost ... unit_cost profit_baseline profit_with_factory roi
0 12.0 12.0 12.0 292 ... 10.1 22.8 33.2 0.035 6
1 12.0 12.0 12.0 276 ... 10.1 22.8 39.7 0.061 4
2 12.0 12.0 12.0 322 ... 10.1 22.8 16.4 -0.020 0
... ... ... ... ... ... ... ... ... ...
2997 12.0 12.0 12.0 399 ... 10.1 22.8 40.8 0.045 2
2998 12.0 12.0 12.0 275 ... 10.1 22.8 39.2 0.059 5
2999 12.0 12.0 12.0 267 ... 10.1 22.8 31.2 0.031 2

API

Get the simulation data (and more) in a machine-readable format: /api/sim/cAK4FKhWdhYVRccnzF2QVn/