More progress on DistGeneric

This commit is contained in:
Ozzie Gooen 2022-06-13 18:13:43 -07:00
parent 6a4132c955
commit 62ed997de2
6 changed files with 135 additions and 101 deletions

View File

@ -142,7 +142,7 @@ module DistributionOperation = {
| ToDist(Scale(#LogarithmWithThreshold(eps), r)) => | ToDist(Scale(#LogarithmWithThreshold(eps), r)) =>
`scaleLogWithThreshold(${E.Float.toFixed(r)}, epsilon=${E.Float.toFixed(eps)})` `scaleLogWithThreshold(${E.Float.toFixed(r)}, epsilon=${E.Float.toFixed(eps)})`
| ToString(ToString) => `toString` | ToString(ToString) => `toString`
| ToString(ToSparkline(n)) => `toSparkline(${E.I.toString(n)})` | ToString(ToSparkline(n)) => `sparkline(${E.I.toString(n)})`
| ToBool(IsNormalized) => `isNormalized` | ToBool(IsNormalized) => `isNormalized`
| ToDistCombination(Algebraic(_), _, _) => `algebraic` | ToDistCombination(Algebraic(_), _, _) => `algebraic`
| ToDistCombination(Pointwise, _, _) => `pointwise` | ToDistCombination(Pointwise, _, _) => `pointwise`

View File

@ -295,7 +295,7 @@ module Float = {
let inv = (p, t: t) => p < t ? 0.0 : 1.0 let inv = (p, t: t) => p < t ? 0.0 : 1.0
let mean = (t: t) => Ok(t) let mean = (t: t) => Ok(t)
let sample = (t: t) => t let sample = (t: t) => t
let toString = (t: t) => j`Delta($t)` let toString = (t: t) => j`PointMass($t)`
let toPointSetDist = (t: t): PointSetTypes.pointSetDist => Discrete( let toPointSetDist = (t: t): PointSetTypes.pointSetDist => Discrete(
Discrete.make(~integralSumCache=Some(1.0), {xs: [t], ys: [1.0]}), Discrete.make(~integralSumCache=Some(1.0), {xs: [t], ys: [1.0]}),
) )

View File

@ -221,9 +221,9 @@ let dispatchToGenericOutput = (
} }
| ("integralSum", [EvDistribution(dist)]) => Helpers.toFloatFn(#IntegralSum, dist, ~env) | ("integralSum", [EvDistribution(dist)]) => Helpers.toFloatFn(#IntegralSum, dist, ~env)
| ("toString", [EvDistribution(dist)]) => Helpers.toStringFn(ToString, dist, ~env) | ("toString", [EvDistribution(dist)]) => Helpers.toStringFn(ToString, dist, ~env)
| ("toSparkline", [EvDistribution(dist)]) => | ("sparkline", [EvDistribution(dist)]) =>
Helpers.toStringFn(ToSparkline(MagicNumbers.Environment.sparklineLength), dist, ~env) Helpers.toStringFn(ToSparkline(MagicNumbers.Environment.sparklineLength), dist, ~env)
| ("toSparkline", [EvDistribution(dist), EvNumber(n)]) => | ("sparkline", [EvDistribution(dist), EvNumber(n)]) =>
Helpers.toStringFn(ToSparkline(Belt.Float.toInt(n)), dist, ~env) Helpers.toStringFn(ToSparkline(Belt.Float.toInt(n)), dist, ~env)
| ("exp", [EvDistribution(a)]) => | ("exp", [EvDistribution(a)]) =>
// https://mathjs.org/docs/reference/functions/exp.html // https://mathjs.org/docs/reference/functions/exp.html

View File

@ -3,14 +3,15 @@ sidebar_position: 3
title: Distribution title: Distribution
--- ---
import Admonition from "@theme/Admonition";
import TOCInline from "@theme/TOCInline";
Distributions are the flagship data type in Squiggle. The distribution type is a generic data type that contains one of three different formats of distributions. Distributions are the flagship data type in Squiggle. The distribution type is a generic data type that contains one of three different formats of distributions.
These subtypes are [point set](/docs/Api/DistPointSet), [sample set](/docs/Api/DistSampleSet), and symbolic. The first two of these have a few custom functions that only work on them. You can read more about the differences between these formats [here](/docs/Discussions/Three-Formats-Of-Distributions). These subtypes are [point set](/docs/Api/DistPointSet), [sample set](/docs/Api/DistSampleSet), and symbolic. The first two of these have a few custom functions that only work on them. You can read more about the differences between these formats [here](/docs/Discussions/Three-Formats-Of-Distributions).
Several functions below only can work on particular distribution formats. Several functions below only can work on particular distribution formats.
For example, scoring and pointwise math requires the point set format. When this happens, the types are automatically converted to the correct format. These conversions are lossy. For example, scoring and pointwise math requires the point set format. When this happens, the types are automatically converted to the correct format. These conversions are lossy.
import TOCInline from "@theme/TOCInline"
<TOCInline toc={toc} /> <TOCInline toc={toc} />
## Distribution Creation ## Distribution Creation
@ -48,9 +49,9 @@ lognormal: (dict<{mean: distribution|number, stdev: distribution|number}>) => di
**Examples** **Examples**
```javascript ```javascript
lognormal(0.5, 0.8) lognormal(0.5, 0.8);
lognormal({ p5: 4, p95: 10 }) lognormal({ p5: 4, p95: 10 });
lognormal({ mean: 5, stdev: 2 }) lognormal({ mean: 5, stdev: 2 });
``` ```
### uniform ### uniform
@ -62,7 +63,7 @@ uniform: (distribution|number, distribution|number) => distribution
**Examples** **Examples**
```javascript ```javascript
uniform(10, 12) uniform(10, 12);
``` ```
### beta ### beta
@ -74,7 +75,7 @@ beta: (distribution|number, distribution|number) => distribution
**Examples** **Examples**
```javascript ```javascript
beta(20, 25) beta(20, 25);
``` ```
### cauchy ### cauchy
@ -86,7 +87,7 @@ cauchy: (distribution|number, distribution|number) => distribution
**Examples** **Examples**
```javascript ```javascript
cauchy(5, 1) cauchy(5, 1);
``` ```
### gamma ### gamma
@ -97,11 +98,11 @@ gamma: (distribution|number, distribution|number) => distribution
**Examples** **Examples**
```javascript ```js
gamma(5, 1) gamma(5, 1);
``` ```
### Logistic ### logistic
``` ```
logistic: (distribution|number, distribution|number) => distribution logistic: (distribution|number, distribution|number) => distribution
@ -110,7 +111,7 @@ logistic: (distribution|number, distribution|number) => distribution
**Examples** **Examples**
```javascript ```javascript
gamma(5, 1) gamma(5, 1);
``` ```
### exponential ### exponential
@ -122,7 +123,7 @@ exponential: (distribution|number) => distribution
**Examples** **Examples**
```javascript ```javascript
exponential(2) exponential(2);
``` ```
### bernoulli ### bernoulli
@ -134,22 +135,22 @@ bernoulli: (distribution|number) => distribution
**Examples** **Examples**
```javascript ```javascript
bernoulli(0.5) bernoulli(0.5);
``` ```
### triangular ### triangular
```javascript ```javascript
triangular: (number, number, number) => distribution triangular: (number, number, number) => distribution;
``` ```
**Examples** **Examples**
```javascript ```javascript
triangular(5, 10, 20) triangular(5, 10, 20);
``` ```
### To / credibleIntervalToDistribution ### to / credibleIntervalToDistribution
The `to` function is an easy way to generate simple distributions using predicted _5th_ and _95th_ percentiles. The `to` function is an easy way to generate simple distributions using predicted _5th_ and _95th_ percentiles.
@ -180,9 +181,9 @@ mixture: (list<distributionLike>, weights?:list<float>) => distribution
**Examples** **Examples**
```javascript ```javascript
mixture(normal(5, 1), normal(10, 1), 8) mixture(normal(5, 1), normal(10, 1), 8);
mx(normal(5, 1), normal(10, 1), [0.3, 0.7]) mx(normal(5, 1), normal(10, 1), [0.3, 0.7]);
mx([normal(5, 1), normal(10, 1)], [0.3, 0.7]) mx([normal(5, 1), normal(10, 1)], [0.3, 0.7]);
``` ```
## Functions ## Functions
@ -198,7 +199,7 @@ sample: (distribution) => number
**Examples** **Examples**
```javascript ```javascript
sample(normal(5, 2)) sample(normal(5, 2));
``` ```
### sampleN ### sampleN
@ -212,7 +213,7 @@ sampleN: (distribution, number) => list<number>
**Examples** **Examples**
```javascript ```javascript
sampleN(normal(5, 2), 100) sampleN(normal(5, 2), 100);
``` ```
### mean ### mean
@ -226,7 +227,7 @@ mean: (distribution) => number
**Examples** **Examples**
```javascript ```javascript
mean(normal(5, 2)) mean(normal(5, 2));
``` ```
### stdev ### stdev
@ -260,7 +261,7 @@ cdf: (distribution, number) => number
**Examples** **Examples**
```javascript ```javascript
cdf(normal(5, 2), 3) cdf(normal(5, 2), 3);
``` ```
### pdf ### pdf
@ -272,7 +273,7 @@ pdf: (distribution, number) => number
**Examples** **Examples**
```javascript ```javascript
pdf(normal(5, 2), 3) pdf(normal(5, 2), 3);
``` ```
### quantile ### quantile
@ -284,7 +285,7 @@ quantile: (distribution, number) => number
**Examples** **Examples**
```javascript ```javascript
quantile(normal(5, 2), 0.5) quantile(normal(5, 2), 0.5);
``` ```
### toPointSet ### toPointSet
@ -300,7 +301,7 @@ toPointSet: (distribution) => pointSetDistribution
**Examples** **Examples**
```javascript ```javascript
toPointSet(normal(5, 2)) toPointSet(normal(5, 2));
``` ```
### toSampleSet ### toSampleSet
@ -316,7 +317,7 @@ toSampleSet: (distribution, number) => sampleSetDistribution
**Examples** **Examples**
```javascript ```javascript
toSampleSet(normal(5, 2), 1000) toSampleSet(normal(5, 2), 1000);
``` ```
### truncateLeft ### truncateLeft
@ -330,7 +331,7 @@ truncateLeft: (distribution, l => number) => distribution
**Examples** **Examples**
```javascript ```javascript
truncateLeft(normal(5, 2), 3) truncateLeft(normal(5, 2), 3);
``` ```
### truncateRight ### truncateRight
@ -344,7 +345,7 @@ truncateRight: (distribution, r => number) => distribution
**Examples** **Examples**
```javascript ```javascript
truncateLeft(normal(5, 2), 6) truncateLeft(normal(5, 2), 6);
``` ```
### klDivergence ### klDivergence
@ -358,7 +359,7 @@ klDivergence: (distribution, distribution) => number
**Examples** **Examples**
```javascript ```javascript
klDivergence(normal(5, 2), normal(5, 4)) // returns 0.57 klDivergence(normal(5, 2), normal(5, 4)); // returns 0.57
``` ```
## Display ## Display
@ -372,26 +373,26 @@ toString: (distribution) => string
**Examples** **Examples**
```javascript ```javascript
toString(normal(5, 2)) toString(normal(5, 2));
``` ```
### toSparkline ### sparkline
Produce a sparkline of length n Produce a sparkline of length n. For example, `▁▁▁▁▁▂▄▆▇██▇▆▄▂▁▁▁▁▁`. These can be useful for testing or quick text visualizations.
``` ```
toSparkline: (distribution, n = 20) => string sparkline: (distribution, n = 20) => string
``` ```
**Examples** **Examples**
```javascript ```javascript
toSparkline(normal(5, 2), 10) toSparkline(truncateLeft(normal(5, 2), 3), 20); // produces ▁▇█████▇▅▄▃▂▂▁▁▁▁▁▁▁
``` ```
### inspect ### inspect
Prints the value of the distribution to the Javascript console, then returns the distribution. Prints the value of the distribution to the Javascript console, then returns the distribution. Useful for debugging.
``` ```
inspect: (distribution) => distribution inspect: (distribution) => distribution
@ -400,11 +401,15 @@ inspect: (distribution) => distribution
**Examples** **Examples**
```javascript ```javascript
inspect(normal(5, 2)) inspect(normal(5, 2)); // logs "normal(5, 2)" to the javascript console and returns the distribution.
``` ```
## Normalization ## Normalization
There are some situations where computation will return unnormalized distributions. This means that their cumulative sums are not equal to 1.0. Unnormalized distributions are not valid for many relevant functions; for example, klDivergence and scoring.
The only functions that do not return normalized distributions are the pointwise arithmetic operations and the scalewise arithmetic operations. If you use these functions, it is recommended that you consider normalizing the resulting distributions.
### normalize ### normalize
Normalize a distribution. This means scaling it appropriately so that it's cumulative sum is equal to 1. Normalize a distribution. This means scaling it appropriately so that it's cumulative sum is equal to 1.
@ -416,7 +421,7 @@ normalize: (distribution) => distribution
**Examples** **Examples**
```javascript ```javascript
normalize(normal(5, 2)) normalize(normal(5, 2));
``` ```
### isNormalized ### isNormalized
@ -430,12 +435,14 @@ isNormalized: (distribution) => bool
**Examples** **Examples**
```javascript ```javascript
isNormalized(normal(5, 2)) // returns true isNormalized(normal(5, 2)); // returns true
``` ```
### integralSum ### integralSum
Get the sum of the integral of a distribution. If the distribution is normalized, this will be 1. **Note: If you have suggestions for better names for this, please let us know.**
Get the sum of the integral of a distribution. If the distribution is normalized, this will be 1.0. This is useful for understanding unnormalized distributions.
``` ```
integralSum: (distribution) => number integralSum: (distribution) => number
@ -444,17 +451,17 @@ integralSum: (distribution) => number
**Examples** **Examples**
```javascript ```javascript
integralSum(normal(5, 2)) integralSum(normal(5, 2));
``` ```
## Regular Arithmetic Operations ## Regular Arithmetic Operations
Regular arithmetic operations cover the basic mathematical operations on distributions. They work much like their equivalent operations on numbers. Regular arithmetic operations cover the basic mathematical operations on distributions. They work much like their equivalent operations on numbers.
The infixes `+`,`-`, `*`, `/`, `^`, `-` are supported for addition, subtraction, multiplication, division, power, and unaryMinus. The infixes `+`,`-`, `*`, `/`, `^` are supported for addition, subtraction, multiplication, division, power, and unaryMinus.
```javascript ```javascript
pointMass(5 + 10) == pointMass(5) + pointMass(10) pointMass(5 + 10) == pointMass(5) + pointMass(10);
``` ```
### add ### add
@ -466,13 +473,13 @@ add: (distributionLike, distributionLike) => distribution
**Examples** **Examples**
```javascript ```javascript
normal(0, 1) + normal(1, 3) // returns normal(1, 3.16...) normal(0, 1) + normal(1, 3); // returns normal(1, 3.16...)
add(normal(0, 1), normal(1, 3)) // returns normal(1, 3.16...) add(normal(0, 1), normal(1, 3)); // returns normal(1, 3.16...)
``` ```
### sum ### sum
**Todo: Not yet implemented for distributions** **Todo: Not yet implemented**
``` ```
sum: (list<distributionLike>) => distribution sum: (list<distributionLike>) => distribution
@ -481,7 +488,7 @@ sum: (list<distributionLike>) => distribution
**Examples** **Examples**
```javascript ```javascript
sum([normal(0, 1), normal(1, 3), uniform(10, 1)]) sum([normal(0, 1), normal(1, 3), uniform(10, 1)]);
``` ```
### multiply ### multiply
@ -541,12 +548,27 @@ unaryMinus: (distribution) => distribution
**Examples** **Examples**
```javascript ```javascript
-normal(5, 2) // same as normal(-5, 2) -normal(5, 2); // same as normal(-5, 2)
unaryMinus(normal(5, 2)) // same as normal(-5, 2) unaryMinus(normal(5, 2)); // same as normal(-5, 2)
``` ```
## Pointwise Arithmetic Operations ## Pointwise Arithmetic Operations
<Admonition type="caution" title="Unnormalized Results">
<p>
Pointwise arithmetic operations typically return unnormalized or completely
invalid distributions. For example, the operation{" "}
<code>normal(5,2) .- uniform(10,12)</code> results in a distribution-like
object with negative probability mass.
</p>
</Admonition>
Pointwise arithmetic operations cover the standard arithmetic operations, but work in a different way than the regular operations. These operate on the y-values of the distributions instead of the x-values. A pointwise addition would add the y-values of two distributions.
The infixes `.+`,`.-`, `.*`, `./`, `.^` are supported for their respective operations.
The `mixture` methods works with pointwise addition.
### dotAdd ### dotAdd
``` ```
@ -585,10 +607,20 @@ dotExp: (distributionLike, distributionLike) => distribution
## Scale Arithmetic Operations ## Scale Arithmetic Operations
### scaleMultiply <Admonition type="caution" title="Likely to change">
<p>
We're planning on removing scale operations in favor of more general
functions soon.
</p>
</Admonition>
``` Scale operations are similar to pointwise operations, but operate on a constant y-value instead of y-values coming from a distribution. You can think about this as scaling a distribution vertically by a constant.
scaleMultiply: (distributionLike, number) => distribution
The following items would be equivalent.
```js
scalePow(normal(5,2), 2)
mapY(normal(5,2), {|y| y ^ 2}) // Not yet available
``` ```
### scalePow ### scalePow
@ -619,7 +651,9 @@ scaleLog10: (distributionLike, number) => distribution
### Declaration (Continuous Functions) ### Declaration (Continuous Functions)
Adds metadata to a function of the input ranges. Works now for numeric and date inputs. This is useful when making predictions. It allows you to limit the domain that your prediction will be used and scored within. Adds metadata to a function of the input ranges. Works now for numeric and date inputs. This is useful when making formal predictions. It allows you to limit the domain that your prediction will be used and scored within.
Declarations are currently experimental and will likely be removed or changed in the future.
``` ```
declareFn: (dict<{fn: lambda, inputs: array<dict<{min: number, max: number}>>}>) => declaration declareFn: (dict<{fn: lambda, inputs: array<dict<{min: number, max: number}>>}>) => declaration

View File

@ -6,7 +6,7 @@ title: Math
### E ### E
``` ```
Math.E: Math.e:
``` ```
Euler's number; ≈ 2.718281828459045 Euler's number; ≈ 2.718281828459045
@ -14,7 +14,7 @@ Euler's number; ≈ 2.718281828459045
### LN2 ### LN2
``` ```
Math.LN2: Math.ln2:
``` ```
Natural logarithm of 2; ≈ 0.6931471805599453 Natural logarithm of 2; ≈ 0.6931471805599453
@ -22,7 +22,7 @@ Natural logarithm of 2; ≈ 0.6931471805599453
### LN10 ### LN10
``` ```
Math.LN10: Math.ln10:
``` ```
Natural logarithm of 10; ≈ 2.302585092994046 Natural logarithm of 10; ≈ 2.302585092994046
@ -30,7 +30,7 @@ Natural logarithm of 10; ≈ 2.302585092994046
### LOG2E ### LOG2E
``` ```
Math.LOG2E: Math.log2e:
``` ```
Base 2 logarithm of E; ≈ 1.4426950408889634Base 2 logarithm of E; ≈ 1.4426950408889634 Base 2 logarithm of E; ≈ 1.4426950408889634Base 2 logarithm of E; ≈ 1.4426950408889634
@ -38,7 +38,7 @@ Base 2 logarithm of E; ≈ 1.4426950408889634Base 2 logarithm of E; ≈ 1.442695
### LOG10E ### LOG10E
``` ```
Math.LOG10E: Math.log10e:
``` ```
Base 10 logarithm of E; ≈ 0.4342944819032518 Base 10 logarithm of E; ≈ 0.4342944819032518
@ -46,7 +46,7 @@ Base 10 logarithm of E; ≈ 0.4342944819032518
### PI ### PI
``` ```
Math.PI: Math.pi:
``` ```
Pi - ratio of the circumference to the diameter of a circle; ≈ 3.141592653589793 Pi - ratio of the circumference to the diameter of a circle; ≈ 3.141592653589793
@ -54,7 +54,7 @@ Pi - ratio of the circumference to the diameter of a circle; ≈ 3.1415926535897
### SQRT1_2 ### SQRT1_2
``` ```
Math.SQRT1_2: Math.sqrt1_2:
``` ```
Square root of 1/2; ≈ 0.7071067811865476 Square root of 1/2; ≈ 0.7071067811865476
@ -62,7 +62,7 @@ Square root of 1/2; ≈ 0.7071067811865476
### SQRT2 ### SQRT2
``` ```
Math.SQRT2: Math.sqrt2:
``` ```
Square root of 2; ≈ 1.4142135623730951 Square root of 2; ≈ 1.4142135623730951
@ -70,7 +70,7 @@ Square root of 2; ≈ 1.4142135623730951
### PHI ### PHI
``` ```
Math.PHI: Math.phi:
``` ```
Phi is the golden ratio. 1.618033988749895 Phi is the golden ratio. 1.618033988749895
@ -78,7 +78,7 @@ Phi is the golden ratio. 1.618033988749895
### TAU ### TAU
``` ```
Math.TAU: Math.tau:
``` ```
Tau is the ratio constant of a circle's circumference to radius, equal to 2 \* pi. 6.283185307179586 Tau is the ratio constant of a circle's circumference to radius, equal to 2 \* pi. 6.283185307179586

View File

@ -9,57 +9,57 @@ import TOCInline from "@theme/TOCInline";
### ceil ### ceil
```javascript ```
ceil: (number) => number; ceil: (number) => number
``` ```
### floor ### floor
```javascript ```
floor: (number) => number; floor: (number) => number
``` ```
### abs ### abs
```javascript ```
abs: (number) => number; abs: (number) => number
``` ```
### round ### round
```javascript ```
round: (number) => number; round: (number) => number
``` ```
## Statistics ## Statistics
### max ### max
```javascript ```
max: (list<number>) => number max: (list<number>) => number
``` ```
### min ### min
```javascript ```
min: (list<number>) => number min: (list<number>) => number
``` ```
### mean ### mean
```javascript ```
mean: (list<number>) => number mean: (list<number>) => number
``` ```
### stdev ### stdev
```javascript ```
stdev: (list<number>) => number stdev: (list<number>) => number
``` ```
### variance ### variance
```javascript ```
variance: (list<number>) => number variance: (list<number>) => number
``` ```
@ -67,25 +67,25 @@ variance: (list<number>) => number
### unaryMinus ### unaryMinus
```javascript ```
unaryMinus: (number) => number; unaryMinus: (number) => number
``` ```
### equal ### equal
```javascript ```
equal: (number, number) => boolean; equal: (number, number) => boolean
``` ```
### add ### add
```javascript ```
add: (number, number) => number; add: (number, number) => number
``` ```
### sum ### sum
```javascript ```
sum: (list<number>) => number sum: (list<number>) => number
``` ```
@ -97,13 +97,13 @@ cumsum: (list<number>) => list<number>
### multiply ### multiply
```javascript ```
multiply: (number, number) => number; multiply: (number, number) => number
``` ```
### product ### product
```javascript ```
product: (list<number>) => number product: (list<number>) => number
``` ```
@ -115,30 +115,30 @@ cumprod: (list<number>) => list<number>
### subtract ### subtract
```javascript ```
subtract: (number, number) => number; subtract: (number, number) => number
``` ```
### divide ### divide
```javascript ```
divide: (number, number) => number; divide: (number, number) => number
``` ```
### pow ### pow
```javascript ```
pow: (number, number) => number; pow: (number, number) => number
``` ```
### exp ### exp
```javascript ```
exp: (number) => number; exp: (number) => number
``` ```
### log ### log
```javascript ```
log: (number) => number; log: (number) => number
``` ```