diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index c7750177..2aef3ae3 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -18,13 +18,6 @@ on: - production - staging - develop - pull_request: - # The branches below must be a subset of the branches above - branches: - - master - - production - - staging - - develop schedule: - cron: "42 19 * * 0" diff --git a/.parcelrc b/.parcelrc deleted file mode 100644 index f5a5c2d5..00000000 --- a/.parcelrc +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends": "@parcel/config-default", - "transformers": { - "*.res": ["@parcel/transformer-raw"] - } -} diff --git a/packages/squiggle-lang/.prettierignore b/packages/squiggle-lang/.prettierignore index 30674e4d..bc218d9b 100644 --- a/packages/squiggle-lang/.prettierignore +++ b/packages/squiggle-lang/.prettierignore @@ -2,3 +2,5 @@ dist lib *.bs.js *.gen.tsx +.nyc_output/ +coverage/ diff --git a/packages/squiggle-lang/src/rescript/Distributions/SymbolicDist/SymbolicDist.res b/packages/squiggle-lang/src/rescript/Distributions/SymbolicDist/SymbolicDist.res index da722036..a6eda12b 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/SymbolicDist/SymbolicDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/SymbolicDist/SymbolicDist.res @@ -86,7 +86,9 @@ module Exponential = { module Cauchy = { type t = cauchy - let make = (local, scale): symbolicDist => #Cauchy({local: local, scale: scale}) + let make = (local, scale): result => Ok( + #Cauchy({local: local, scale: scale}), + ) let pdf = (x, t: t) => Jstat.Cauchy.pdf(x, t.local, t.scale) let cdf = (x, t: t) => Jstat.Cauchy.cdf(x, t.local, t.scale) let inv = (p, t: t) => Jstat.Cauchy.inv(p, t.local, t.scale) diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res index 90e79e8e..b1befa5a 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res @@ -44,7 +44,7 @@ let defaultBindings: T.bindings = Belt.Map.String.empty /* Recursively evaluate/reduce the expression (Lisp AST) */ -let rec reduceExpression = (expression: t, bindings: T.bindings): result => { +let reduceExpression = (expression: t, bindings: T.bindings): result => { /* After reducing each level of expression(Lisp AST), we have a value list to evaluate */ @@ -135,6 +135,7 @@ let rec reduceExpression = (expression: t, bindings: T.bindings): resultResult.flatMap(acc => acc->doMacroCall(bindings)) } + | T.EBindings(bindings) => T.EBindings(bindings)->Ok } let rec reduceExpandedExpression = (expression: t): result => @@ -155,6 +156,7 @@ let rec reduceExpression = (expression: t, bindings: T.bindings): resultResult.flatMap(acc => acc->reduceValueList) } + | T.EBindings(bindings) => RETodo("Cannot return bindings")->Error } let rExpandedExpression: result = expression->seekMacros(bindings) diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res index f7381f07..a15c4082 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res @@ -149,6 +149,7 @@ module SymbolicConstructors = { | "uniform" => Ok(SymbolicDist.Uniform.make) | "beta" => Ok(SymbolicDist.Beta.make) | "lognormal" => Ok(SymbolicDist.Lognormal.make) + | "cauchy" => Ok(SymbolicDist.Cauchy.make) | "to" => Ok(SymbolicDist.From90thPercentile.make) | _ => Error("Unreachable state") } @@ -182,7 +183,7 @@ let dispatchToGenericOutput = (call: ExpressionValue.functionCall): option< ->E.R.bind(r => r(f1)) ->SymbolicConstructors.symbolicResultToOutput | ( - ("normal" | "uniform" | "beta" | "lognormal" | "to") as fnName, + ("normal" | "uniform" | "beta" | "lognormal" | "cauchy" | "to") as fnName, [EvNumber(f1), EvNumber(f2)], ) => SymbolicConstructors.twoFloat(fnName) diff --git a/packages/website/.prettierignore b/packages/website/.prettierignore new file mode 100644 index 00000000..d858cd65 --- /dev/null +++ b/packages/website/.prettierignore @@ -0,0 +1,2 @@ +.docusaurus +build diff --git a/packages/website/docs/Features/Functions.mdx b/packages/website/docs/Features/Functions.mdx index 7e0d1fc6..c85a3438 100644 --- a/packages/website/docs/Features/Functions.mdx +++ b/packages/website/docs/Features/Functions.mdx @@ -1,12 +1,15 @@ --- +title: "Functions Reference" sidebar_position: 7 --- import { SquiggleEditor } from "../../src/components/SquiggleEditor"; -# Squiggle Functions Reference +_The source of truth for this document is [this file of code](https://github.com/quantified-uncertainty/squiggle/blob/develop/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res)_ -## Distributions +## Inventory distributions + +We provide starter distributions, computed symbolically. ### Normal distribution @@ -15,6 +18,10 @@ and standard deviation. +#### Validity + +- `sd > 0` + ### Uniform distribution The `uniform(low, high)` function creates a uniform distribution between the @@ -22,86 +29,281 @@ two given numbers. +#### Validity + +- `low < high` + ### Lognormal distribution The `lognormal(mu, sigma)` returns the log of a normal distribution with parameters -mu and sigma. The log of lognormal(mu, sigma) is a normal distribution with parameters -mean mu and standard deviation sigma. +`mu` and `sigma`. The log of `lognormal(mu, sigma)` is a normal distribution with mean `mu` and standard deviation `sigma`. -An alternative format is also available. The "to" notation creates a lognormal +An alternative format is also available. The `to` notation creates a lognormal distribution with a 90% confidence interval between the two numbers. We add -this convinience as lognormal distributions are commonly used in practice. +this convenience as lognormal distributions are commonly used in practice. +#### Future feature: + Furthermore, it's also possible to create a lognormal from it's actual mean and standard deviation, using `lognormalFromMeanAndStdDev`. +TODO: interpreter/parser doesn't provide this in current `develop` branch + +#### Validity + +- `sigma > 0` +- In `x to y` notation, `x < y` + ### Beta distribution -The `beta(a, b)` function creates a beta distribution with parameters a and b: +The `beta(a, b)` function creates a beta distribution with parameters `a` and `b`: - + + +#### Validity + +- `a > 0` +- `b > 0` +- Empirically, we have noticed that numerical instability arises when `a < 1` or `b < 1` ### Exponential distribution -The `exponential(mean)` function creates an exponential distribution with the given -mean. +The `exponential(rate)` function creates an exponential distribution with the given +rate. - + -### The Triangular distribution +#### Validity + +- `rate > 0` + +### Triangular distribution The `triangular(a,b,c)` function creates a triangular distribution with lower -bound a, mode b and upper bound c. +bound `a`, mode `b` and upper bound `c`. + +#### Validity + +- `a < b < c` -### Multimodal distriutions +### Scalar (constant dist) -The multimodal function combines 2 or more other distributions to create a weighted +Squiggle, when the context is right, automatically casts a float to a constant distribution. + +## Operating on distributions + +Here are the ways we combine distributions. + +### Mixture of distributions + +The `mixture` function combines 2 or more other distributions to create a weighted combination of the two. The first positional arguments represent the distributions to be combined, and the last argument is how much to weigh every distribution in the combination. - + It's possible to create discrete distributions using this method. - + As well as mixed distributions: - + -## Other Functions +An alias of `mixture` is `mx` -### PDF of a distribution +#### Validity -The `pdf(distribution, x)` function returns the density of a distribution at the +Using javascript's variable arguments notation, consider `mx(...dists, weights)`: + +- `dists.length == weights.length` + +### Addition + +A horizontal right shift + + + +### Subtraction + +A horizontal left shift + + + +### Multiplication + +TODO: provide intuition pump for the semantics + + + +We also provide concatenation of two distributions as a syntax sugar for `*` + + + +### Division + +TODO: provide intuition pump for the semantics + + + +### Exponentiation + +TODO: provide intuition pump for the semantics + + + +### Taking the base `e` exponential + + + +### Taking logarithms + + + + + +Base `x` + + + +#### Validity + +- `x` must be a scalar +- See [the current discourse](https://github.com/quantified-uncertainty/squiggle/issues/304) + +### Pointwise addition + +**Pointwise operations are done with `PointSetDist` internals rather than `SampleSetDist` internals**. + +TODO: this isn't in the new interpreter/parser yet. + + + +### Pointwise subtraction + +TODO: this isn't in the new interpreter/parser yet. + + + +### Pointwise multiplication + + + +### Pointwise division + + + +### Pointwise exponentiation + + + +### Pointwise logarithm + +TODO: write about the semantics and the case handling re scalar vs. dist and log base. + + + +## Standard functions on distributions + +### Probability density function + +The `pdf(dist, x)` function returns the density of a distribution at the given point x. -### Inverse of a distribution +#### Validity -The `inv(distribution, prob)` gives the value x or which the probability for all values -lower than x is equal to prob. It is the inverse of `cdf`. +- `x` must be a scalar +- `dist` must be a distribution - +### Cumulative density function -### CDF of a distribution - -The `cdf(distribution,x)` gives the cumulative probability of the distribution +The `cdf(dist, x)` gives the cumulative probability of the distribution or all values lower than x. It is the inverse of `inv`. -### Mean of a distribution +#### Validity + +- `x` must be a scalar +- `dist` must be a distribution + +### Inverse CDF + +The `inv(dist, prob)` gives the value x or which the probability for all values +lower than x is equal to prob. It is the inverse of `cdf`. + + + +#### Validity + +- `prob` must be a scalar (please only put it in `(0,1)`) +- `dist` must be a distribution + +### Mean The `mean(distribution)` function gives the mean (expected value) of a distribution. @@ -112,3 +314,55 @@ The `mean(distribution)` function gives the mean (expected value) of a distribut The `sample(distribution)` samples a given distribution. + +## Normalization + +Some distribution operations (like horizontal shift) return an unnormalized distriibution. + +We provide a `normalize` function + + + +#### Validity - Input to `normalize` must be a dist + +We provide a predicate `isNormalized`, for when we have simple control flow + + + +#### Validity + +- Input to `isNormalized` must be a dist + +## Convert any distribution to a sample set distribution + +`toSampleSet` has two signatures + +It is unary when you use an internal hardcoded number of samples + + + +And binary when you provide a number of samples (floored) + + + +## `inspect` + +You may like to debug by right clicking your browser and using the _inspect_ functionality on the webpage, and viewing the _console_ tab. Then, wrap your squiggle output with `inspect` to log an internal representation. + + + +Save for a logging side effect, `inspect` does nothing to input and returns it. + +## Truncate + +You can cut off from the left + + + +You can cut off from the right + + + +You can cut off from both sides + + diff --git a/packages/website/docs/Internal/Invariants.md b/packages/website/docs/Internal/Invariants.md index c1c0fd79..91adf1a1 100644 --- a/packages/website/docs/Internal/Invariants.md +++ b/packages/website/docs/Internal/Invariants.md @@ -1,5 +1,5 @@ --- -title: Statistical properties of algebraic combinations of distributions for property testing. +title: Invariants of Probability Distributions urlcolor: blue author: - Nuño Sempere @@ -7,13 +7,17 @@ author: abstract: This document outlines some properties about algebraic combinations of distributions. It is meant to facilitate property tests for [Squiggle](https://squiggle-language.com/), an estimation language for forecasters. So far, we are focusing on the means, the standard deviation and the shape of the pdfs. --- +Invariants to check with property tests. + _This document right now is normative and aspirational, not a description of the testing that's currently done_. +## Algebraic combinations + The academic keyword to search for in relation to this document is "[algebra of random variables](https://wikiless.org/wiki/Algebra_of_random_variables?lang=en)". Squiggle doesn't yet support getting the standard deviation, denoted by $\sigma$, but such support could yet be added. -## Means and standard deviations +### Means and standard deviations -### Sums +#### Sums $$ mean(f+g) = mean(f) + mean(g) @@ -29,7 +33,7 @@ $$ mean(normal(a,b) + normal(c,d)) = mean(normal(a+c, \sqrt{b^2 + d^2})) $$ -### Subtractions +#### Subtractions $$ mean(f-g) = mean(f) - mean(g) @@ -39,7 +43,7 @@ $$ \sigma(f-g) = \sqrt{\sigma(f)^2 + \sigma(g)^2} $$ -### Multiplications +#### Multiplications $$ mean(f \cdot g) = mean(f) \cdot mean(g) @@ -49,15 +53,15 @@ $$ \sigma(f \cdot g) = \sqrt{ (\sigma(f)^2 + mean(f)) \cdot (\sigma(g)^2 + mean(g)) - (mean(f) \cdot mean(g))^2} $$ -### Divisions +#### Divisions Divisions are tricky, and in general we don't have good expressions to characterize properties of ratios. In particular, the ratio of two normals is a Cauchy distribution, which doesn't have to have a mean. -## Probability density functions (pdfs) +### Probability density functions (pdfs) Specifying the pdf of the sum/multiplication/... of distributions as a function of the pdfs of the individual arguments can still be done. But it requires integration. My sense is that this is still doable, and I (Nuño) provide some _pseudocode_ to do this. -### Sums +#### Sums Let $f, g$ be two independently distributed functions. Then, the pdf of their sum, evaluated at a point $z$, expressed as $(f + g)(z)$, is given by: @@ -110,15 +114,31 @@ let pdfOfSum = (pdf1, pdf2, cdf1, cdf2, z) => { }; ``` -## Cumulative density functions +### Cumulative density functions TODO -## Inverse cumulative density functions +### Inverse cumulative density functions TODO -# To do: +## `pdf`, `cdf`, and `inv` + +With $\forall dist, pdf := x \mapsto \texttt{pdf}(dist, x) \land cdf := x \mapsto \texttt{cdf}(dist, x) \land inv := p \mapsto \texttt{inv}(dist, p)$, + +### `cdf` and `inv` are inverses + +$$ +\forall x \in (0,1), cdf(inv(x)) = x \land \forall x \in \texttt{dom}(cdf), x = inv(cdf(x)) +$$ + +### The codomain of `cdf` equals the open interval `(0,1)` equals the codomain of `pdf` + +$$ +\texttt{cod}(cdf) = (0,1) = \texttt{cod}(pdf) +$$ + +## To do: - Provide sources or derivations, useful as this document becomes more complicated - Provide definitions for the probability density function, exponential, inverse, log, etc. diff --git a/packages/website/docusaurus.config.js b/packages/website/docusaurus.config.js index c5d03327..4971b1b0 100644 --- a/packages/website/docusaurus.config.js +++ b/packages/website/docusaurus.config.js @@ -49,7 +49,7 @@ const config = { sidebarPath: require.resolve("./sidebars.js"), // Please change this to your repo. editUrl: - "https://github.com/quantified-uncertainty/squiggle/tree/master/packages/website/", + "https://github.com/quantified-uncertainty/squiggle/tree/develop/packages/website/", remarkPlugins: [math], rehypePlugins: [katex], }, @@ -57,7 +57,7 @@ const config = { showReadingTime: true, // Please change this to your repo. editUrl: - "https://github.com/quantified-uncertainty/squiggle/tree/master/packages/website/", + "https://github.com/quantified-uncertainty/squiggle/tree/develop/packages/website/", }, theme: { customCss: require.resolve("./src/css/custom.css"), @@ -73,7 +73,7 @@ const config = { title: "Squiggle", logo: { alt: "Squiggle Logo", - src: "img/logo.svg", + src: "img/quri-logo.png", }, items: [ { @@ -85,7 +85,7 @@ const config = { { to: "/blog", label: "Blog", position: "left" }, { to: "/playground", label: "Playground", position: "left" }, { - href: "https://github.com/QURIresearch/squiggle", + href: "https://github.com/quantified-uncertainty/squiggle", label: "GitHub", position: "right", }, @@ -103,7 +103,7 @@ const config = { }, { label: "GitHub", - href: "https://github.com/QURIresearch/squiggle", + href: "https://github.com/quantified-uncertainty/squiggle", }, ], }, diff --git a/packages/website/src/pages/index.js b/packages/website/src/pages/index.js index 452c7ef0..4cbddcac 100644 --- a/packages/website/src/pages/index.js +++ b/packages/website/src/pages/index.js @@ -22,10 +22,7 @@ function HomepageHeader() { export default function Home() { const { siteConfig } = useDocusaurusContext(); return ( - +
diff --git a/packages/website/static/img/favicon.ico b/packages/website/static/img/favicon.ico index c01d54bc..d318e234 100644 Binary files a/packages/website/static/img/favicon.ico and b/packages/website/static/img/favicon.ico differ diff --git a/packages/website/static/img/quri-logo.png b/packages/website/static/img/quri-logo.png new file mode 100644 index 00000000..14932c80 Binary files /dev/null and b/packages/website/static/img/quri-logo.png differ