Skip to content

Explosions and estimates

tilttek/dice-probability

Settings

new Settings(int $explosionDepth = 10, int $workLimit = 500_000, int $samples = 20_000, int $seed = 0, int $rollLimit = 200_000);
SettingWhat it bounds
explosionDepthHow many explosions per die the exact computation follows
workLimitHow much work an exact computation does at most — each weight multiplied or added counts one while the weights are small, more as they grow
samplesHow many rolls an estimate is drawn from
seedThe seed of those rolls: the same seed gives the same estimate
rollLimitHow many dice an estimate rolls at most over all its samples, explosions and rerolls included

Each bound is at least 1. Together, the work limit and the roll limit bound the work of any expression: at the defaults, about a second of processor time for the exact computation and as much for an estimate.

Explosions

An explosion without limit could go on forever. The computation follows each die to explosionDepth explosions; the values of the rolls that would have exploded further are counted as they stand there, a little low. Their probability is the distribution's remaining: for 1d6! at the default depth, 1/362797056, one chance in six to the eleventh power; for a set of dice, the probability that any of them went that far. An explosion whose limit is at most the depth — 1d6!(3) — is exact, and nothing remains.

Estimates

Past the work limit, or for a construct the exact computation does not follow, the result is drawn from samples rolls of the library's own roller, seeded with seed: each weight is the number of rolls that gave the value, over the number of rolls. The result says so:

$distribution->isEstimated();          // true
$distribution->estimate->reason;       // EstimateReason::TooLarge or EstimateReason::Unsupported
$distribution->estimate->samples;      // 20000
$distribution->estimate->margin();     // 0.0069: each probability is within 0.69 points, 19 times out of 20

The margin is the half-width of the 95 % confidence interval of a probability in the worst case, one half: 1.96 × √(0.25 / samples). An estimate states no remaining: its rolls explode as far as the limits of a roll let them.

ReasonWhen
TooLargeThe exact computation would go past the work limit: 50d20kh10, 100d100 with selections
UnsupportedUnique dice, dice all the same that explode, occurrences, groups, filters of the whole set, the dice before, a selection among dice that explode into dice of their own, equal values that contribute differently to a selection, dice of the application whose faces are not known

The cost of an exact computation, as a guide: 30d6 is about 7 200 operations and 10d6! about 300 000; a selection among many dice of many sides grows fastest, and 50d20kh10 goes past the default limit. The weights of many dice are numbers of many limbs: an operation on them counts one more for every sixteen products of limbs, and a fraction brought to its lowest terms — the probability that an explosion was cut, for one — the cube of its size in limbs.

The roll limit

An estimate rolls samples times, and each roll may throw many dice: 100d6! throws a hundred and twenty on average, 2.4 million dice over twenty thousand samples. Past rollLimit dice, the estimate stops and the call throws CannotCompute (see Exceptions) rather than run on. Lower the samples, or raise the roll limit, for the expressions that need it:

new Probabilities(settings: new Settings(samples: 2_000));          // 100d6!: about 240 000 dice, still too many
new Probabilities(settings: new Settings(rollLimit: 3_000_000));    // 100d6!: allowed, about ten seconds