diff --git a/packages/components/README.md b/packages/components/README.md index ad35c67f..03eb5750 100644 --- a/packages/components/README.md +++ b/packages/components/README.md @@ -1,9 +1,9 @@ [![npm version](https://badge.fury.io/js/@quri%2Fsquiggle-components.svg)](https://www.npmjs.com/package/@quri/squiggle-components) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/quantified-uncertainty/squiggle/blob/develop/LICENSE) -# Squiggle Components +# Squiggle components -This package contains all the components for squiggle. These can be used either as a library or hosted as a [storybook](https://storybook.js.org/). +This package contains the react components for squiggle. These can be used either as a library or hosted as a [storybook](https://storybook.js.org/). # Usage in a `react` project @@ -17,7 +17,10 @@ Add to `App.js`: ```jsx import { SquiggleEditor } from "@quri/squiggle-components"; -; +; ``` # Build storybook for development @@ -38,9 +41,3 @@ Run a development server ```sh yarn start ``` - -And build artefacts for production, - -```sh -yarn build # builds storybook app -``` diff --git a/packages/components/package.json b/packages/components/package.json index 3b50afbf..4888a0a5 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,13 +1,13 @@ { "name": "@quri/squiggle-components", - "version": "0.2.15", + "version": "0.2.17", "license": "MIT", "dependencies": { - "@quri/squiggle-lang": "^0.2.7", + "@quri/squiggle-lang": "^0.2.8", "@react-hook/size": "^2.1.2", "lodash": "^4.17.21", "react": "^18.1.0", - "react-ace": "10.1.0", + "react-ace": "^10.1.0", "react-dom": "^18.1.0", "react-vega": "^7.5.0", "styled-components": "^5.3.5", @@ -36,7 +36,7 @@ "@types/styled-components": "^5.1.24", "@types/webpack": "^5.28.0", "cross-env": "^7.0.3", - "react-scripts": "5.0.1", + "react-scripts": "^5.0.1", "style-loader": "^3.3.1", "ts-loader": "^9.2.9", "tsconfig-paths-webpack-plugin": "^3.5.2", @@ -49,11 +49,11 @@ "scripts": { "start": "cross-env REACT_APP_FAST_REFRESH=false && start-storybook -p 6006 -s public", "build": "tsc -b && build-storybook -s public", - "build:package": "tsc -b", "bundle": "webpack", "all": "yarn bundle && yarn build", "lint": "prettier --check .", - "format": "prettier --write ." + "format": "prettier --write .", + "prepack": "yarn bundle && tsc -b" }, "eslintConfig": { "extends": [ @@ -87,7 +87,6 @@ "@types/react": "17.0.43" }, "source": "./src/index.ts", - "browser": "dist/bundle.js", - "main": "dist/src/index.js", - "types": "dist/src/index.d.ts" + "main": "./dist/src/index.js", + "types": "./dist/src/index.d.ts" } diff --git a/packages/components/src/components/SquiggleChart.tsx b/packages/components/src/components/SquiggleChart.tsx index 31cd9787..699a7e28 100644 --- a/packages/components/src/components/SquiggleChart.tsx +++ b/packages/components/src/components/SquiggleChart.tsx @@ -144,8 +144,6 @@ export interface SquiggleChartProps { diagramStop?: number; /** If the result is a function, how many points along the function it samples */ diagramCount?: number; - /** variables declared before this expression */ - environment?: unknown; /** When the environment changes */ onChange?(expr: squiggleExpression): void; /** CSS width of the element */ diff --git a/packages/components/src/components/SquiggleEditor.tsx b/packages/components/src/components/SquiggleEditor.tsx index 2c01f72f..23686a4f 100644 --- a/packages/components/src/components/SquiggleEditor.tsx +++ b/packages/components/src/components/SquiggleEditor.tsx @@ -32,16 +32,14 @@ export interface SquiggleEditorProps { diagramStop?: number; /** If the result is a function, how many points along the function it samples */ diagramCount?: number; - /** The environment, other variables that were already declared */ - environment?: unknown; /** when the environment changes. Used again for notebook magic*/ onChange?(expr: squiggleExpression): void; /** The width of the element */ - width: number; + width?: number; /** Previous variable declarations */ - bindings: bindings; + bindings?: bindings; /** JS Imports */ - jsImports: jsImports; + jsImports?: jsImports; } const Input = styled.div` @@ -61,7 +59,6 @@ export let SquiggleEditor: React.FC = ({ diagramStop, diagramCount, onChange, - environment, bindings = defaultBindings, jsImports = defaultImports, }: SquiggleEditorProps) => { @@ -87,7 +84,6 @@ export let SquiggleEditor: React.FC = ({ diagramStart={diagramStart} diagramStop={diagramStop} diagramCount={diagramCount} - environment={environment} onChange={onChange} bindings={bindings} jsImports={jsImports} @@ -145,8 +141,6 @@ export interface SquigglePartialProps { diagramCount?: number; /** when the environment changes. Used again for notebook magic*/ onChange?(expr: bindings): void; - /** The width of the element */ - width: number; /** Previously declared variables */ bindings?: bindings; /** Variables imported from js */ diff --git a/packages/squiggle-lang/README.md b/packages/squiggle-lang/README.md index 05bb969c..f6735454 100644 --- a/packages/squiggle-lang/README.md +++ b/packages/squiggle-lang/README.md @@ -3,7 +3,26 @@ # Squiggle language -## Build for development +_An estimation language_ + +# Use the `npm` package + +For instance, in a javascript project, you can + +```sh +yarn add @quri/squiggle-lang +``` + +```js +import { run } from "@quri/squiggle-lang"; +run( + "normal(0, 1) * fromSamples([-3,-2,-1,1,2,3,3,3,4,9]" +).value.value.toSparkline().value; +``` + +**However, for most use cases you'll prefer to use our [library of react components](https://www.npmjs.com/package/@quri/squiggle-components)**, and let your app transitively depend on `@quri/squiggle-lang`. + +# Build for development We assume that you ran `yarn` at the monorepo level. @@ -23,7 +42,7 @@ yarn test yarn coverage:rescript; o _coverage/index.html # produces coverage report and opens it in browser ``` -## Distributing this package or using this package from other monorepo packages +# Distributing this package or using this package from other monorepo packages As it says in the other `packages/*/README.md`s, building this package is an essential step of building other packages. diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros_test.res index eb6e6c0d..7bbc43dd 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros_test.res @@ -7,18 +7,18 @@ module ExpressionT = Reducer_Expression_T let exampleExpression = eNumber(1.) let exampleExpressionY = eSymbol("y") -let exampleStatement = eLetStatement("y", eNumber(1.)) +let exampleStatementY = eLetStatement("y", eNumber(1.)) let exampleStatementX = eLetStatement("y", eSymbol("x")) let exampleStatementZ = eLetStatement("z", eSymbol("y")) -// If it is not a mactro then it is not expanded +// If it is not a macro then it is not expanded testMacro([], exampleExpression, "Ok(1)") describe("bindStatement", () => { // A statement is bound by the bindings created by the previous statement - testMacro([], eBindStatement(eBindings([]), exampleStatement), "Ok((:$setBindings {} :y 1))") + testMacro([], eBindStatement(eBindings([]), exampleStatementY), "Ok((:$setBindings {} :y 1))") // Then it answers the bindings for the next statement when reduced - testMacroEval([], eBindStatement(eBindings([]), exampleStatement), "Ok({y: 1})") + testMacroEval([], eBindStatement(eBindings([]), exampleStatementY), "Ok({y: 1})") // Now let's feed a binding to see what happens testMacro( [], @@ -30,7 +30,7 @@ describe("bindStatement", () => { // When bindings from previous statement are missing the context is injected. This must be the first statement of a block testMacro( [("z", EvNumber(99.))], - eBindStatementDefault(exampleStatement), + eBindStatementDefault(exampleStatementY), "Ok((:$setBindings {z: 99} :y 1))", ) }) @@ -41,19 +41,19 @@ describe("bindExpression", () => { // When an let statement is the end expression then bindings are returned testMacro( [], - eBindExpression(eBindings([("x", EvNumber(2.))]), exampleStatement), + eBindExpression(eBindings([("x", EvNumber(2.))]), exampleStatementY), "Ok((:$exportBindings (:$setBindings {x: 2} :y 1)))", ) // Now let's reduce that expression testMacroEval( [], - eBindExpression(eBindings([("x", EvNumber(2.))]), exampleStatement), + eBindExpression(eBindings([("x", EvNumber(2.))]), exampleStatementY), "Ok({x: 2,y: 1})", ) // When bindings are missing the context is injected. This must be the first and last statement of a block testMacroEval( [("z", EvNumber(99.))], - eBindExpressionDefault(exampleStatement), + eBindExpressionDefault(exampleStatementY), "Ok({y: 1,z: 99})", ) }) @@ -63,22 +63,22 @@ describe("block", () => { testMacro([], eBlock(list{exampleExpression}), "Ok((:$$bindExpression 1))") testMacroEval([], eBlock(list{exampleExpression}), "Ok(1)") // Block with a single statement - testMacro([], eBlock(list{exampleStatement}), "Ok((:$$bindExpression (:$let :y 1)))") - testMacroEval([], eBlock(list{exampleStatement}), "Ok({y: 1})") + testMacro([], eBlock(list{exampleStatementY}), "Ok((:$$bindExpression (:$let :y 1)))") + testMacroEval([], eBlock(list{exampleStatementY}), "Ok({y: 1})") // Block with a statement and an expression testMacro( [], - eBlock(list{exampleStatement, exampleExpressionY}), + eBlock(list{exampleStatementY, exampleExpressionY}), "Ok((:$$bindExpression (:$$bindStatement (:$let :y 1)) :y))", ) - testMacroEval([], eBlock(list{exampleStatement, exampleExpressionY}), "Ok(1)") + testMacroEval([], eBlock(list{exampleStatementY, exampleExpressionY}), "Ok(1)") // Block with a statement and another statement testMacro( [], - eBlock(list{exampleStatement, exampleStatementZ}), + eBlock(list{exampleStatementY, exampleStatementZ}), "Ok((:$$bindExpression (:$$bindStatement (:$let :y 1)) (:$let :z :y)))", ) - testMacroEval([], eBlock(list{exampleStatement, exampleStatementZ}), "Ok({y: 1,z: 1})") + testMacroEval([], eBlock(list{exampleStatementY, exampleStatementZ}), "Ok({y: 1,z: 1})") // Block inside a block testMacro( [], diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res new file mode 100644 index 00000000..69e20067 --- /dev/null +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res @@ -0,0 +1,17 @@ +open Jest +open Reducer_TestHelpers + +Skip.describe("function trics", () => { + testEvalToBe("f(x,y)=x(y); f(f)", "????") + testEvalToBe("f(x)=x(y); f(f)", "????") + testEvalToBe("f(x)=x; f(f)", "????") + + testEvalToBe("f(x,y)=x(y); f(z)", "????") + testEvalToBe("f(x,y)=x(y); f(2)", "????") //prevent js error + testEvalToBe("f(x)=f(y)=2; f(2)", "????") //prevent multiple assignment + testEvalToBe("f(x)=x+1; g(x)=f(x)+1;g(2)", "????") //TODO: f is not found + testEvalToBe("y=2;g(x)=y+1;g(2)", "????") //TODO : y is not found + testEvalToBe("y=2;g(x)=inspect(y)+1", "????") //TODO : 666 + testEvalToBe("f(x,y)=x+y; f(1,2,3,4)", "????") //TODO : arity)) + testEvalToBe("f(x,y)=x+y; f(1)", "????") //TODO : arity)) +}) \ No newline at end of file diff --git a/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_test.res b/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_test.res index 2c0cc3e6..bb330479 100644 --- a/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_test.res +++ b/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_test.res @@ -132,7 +132,8 @@ describe("parse on distribution functions", () => { testParse( ~skip=true, "normal(5,2) .- normal(5,1)", - "Ok((:$$block (:dotPow (:normal 5 2) (:normal 5 1))))", + "Ok((:$$block (:dotSubtract (:normal 5 2) (:normal 5 1))))", + // TODO: !!! returns "Ok((:$$block (:dotPow (:normal 5 2) (:normal 5 1))))" ) testParse( "normal(5,2) .* normal(5,1)", diff --git a/packages/squiggle-lang/__tests__/TS/SampleSet_test.ts b/packages/squiggle-lang/__tests__/TS/SampleSet_test.ts index a617010b..2c77e210 100644 --- a/packages/squiggle-lang/__tests__/TS/SampleSet_test.ts +++ b/packages/squiggle-lang/__tests__/TS/SampleSet_test.ts @@ -1,5 +1,5 @@ import { Distribution } from "../../src/js/index"; -import { expectErrorToBeBounded, failDefault } from "./TestHelpers"; +import { expectErrorToBeBounded, failDefault, testRun } from "./TestHelpers"; import * as fc from "fast-check"; // Beware: float64Array makes it appear in an infinite loop. @@ -212,3 +212,18 @@ describe("mean is mean", () => { ); }); }); + +describe("fromSamples function", () => { + test.skip("gives a mean near the mean of the input", () => { + fc.assert( + fc.property(arrayGen(), (xs_) => { + let xs = Array.from(xs_); + let xsString = xs.toString(); + let squiggleString = `x = fromSamples([${xsString}]); mean(x)`; + let squiggleResult = testRun(squiggleString); + let mean = xs.reduce((a, b) => a + b, 0.0) / xs.length; + expect(squiggleResult.value).toBeCloseTo(mean, 4); + }) + ); + }); +}); diff --git a/packages/squiggle-lang/package.json b/packages/squiggle-lang/package.json index 4d146ef8..40f7e7c7 100644 --- a/packages/squiggle-lang/package.json +++ b/packages/squiggle-lang/package.json @@ -1,6 +1,6 @@ { "name": "@quri/squiggle-lang", - "version": "0.2.7", + "version": "0.2.8", "homepage": "https://squiggle-language.com", "license": "MIT", "scripts": { @@ -24,6 +24,7 @@ "format:rescript": "rescript format -all", "format:prettier": "prettier --write .", "format": "yarn format:rescript && yarn format:prettier", + "prepack": "yarn build && yarn test && yarn bundle", "all": "yarn build && yarn bundle && yarn test" }, "keywords": [ @@ -35,22 +36,22 @@ "rescript": "^9.1.4", "jstat": "^1.9.5", "pdfast": "^0.2.0", - "mathjs": "10.5.0" + "mathjs": "^10.5.0" }, "devDependencies": { "bisect_ppx": "^2.7.1", - "lodash": "4.17.21", + "lodash": "^4.17.21", "rescript-fast-check": "^1.1.1", "@glennsl/rescript-jest": "^0.9.0", "@istanbuljs/nyc-config-typescript": "^1.0.2", "@types/jest": "^27.4.0", "babel-plugin-transform-es2015-modules-commonjs": "^6.26.2", "chalk": "^5.0.1", - "codecov": "3.8.3", - "fast-check": "2.25.0", + "codecov": "^3.8.3", + "fast-check": "^2.25.0", "gentype": "^4.3.0", "jest": "^27.5.1", - "moduleserve": "0.9.1", + "moduleserve": "^0.9.1", "nyc": "^15.1.0", "reanalyze": "^2.19.0", "ts-jest": "^27.1.4", diff --git a/packages/squiggle-lang/src/js/index.ts b/packages/squiggle-lang/src/js/index.ts index 9b916d13..abb563ed 100644 --- a/packages/squiggle-lang/src/js/index.ts +++ b/packages/squiggle-lang/src/js/index.ts @@ -8,6 +8,15 @@ import { externalBindings, expressionValue, errorValue, + distributionError, + toPointSet, + continuousShape, + discreteShape, + distributionErrorToString, + internalCode, + mixedShape, + sampleSetDist, + symbolicDist, } from "../rescript/TypescriptInterface.gen"; export { makeSampleSetDist, @@ -32,6 +41,53 @@ import { Distribution } from "./distribution"; export { Distribution, squiggleExpression, result, resultMap }; +export let defaultSamplingInputs: samplingParams = { + sampleCount: 10000, + xyPointLength: 10000, +}; + +export type result = + | { + tag: "Ok"; + value: a; + } + | { + tag: "Error"; + value: b; + }; + +export function resultMap( + r: result, + mapFn: (x: a) => b +): result { + if (r.tag === "Ok") { + return { tag: "Ok", value: mapFn(r.value) }; + } else { + return r; + } +} + +function Ok(x: a): result { + return { tag: "Ok", value: x }; +} + +type tagged = { tag: a; value: b }; + +function tag(x: a, y: b): tagged { + return { tag: x, value: y }; +} + +export type squiggleExpression = + | tagged<"symbol", string> + | tagged<"string", string> + | tagged<"call", string> + | tagged<"lambda", [string[], internalCode]> + | tagged<"array", squiggleExpression[]> + | tagged<"boolean", boolean> + | tagged<"distribution", Distribution> + | tagged<"number", number> + | tagged<"record", { [key: string]: squiggleExpression }>; + export function run( squiggleString: string, bindings?: externalBindings, diff --git a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res index 29976711..1af12e1a 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res +++ b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res @@ -159,6 +159,16 @@ let rec run = (~env, functionCallInfo: functionCallInfo): outputType => { ->GenericDist.toPointSet(~xyPointLength, ~sampleCount, ()) ->E.R2.fmap(r => Dist(PointSet(r))) ->OutputLocal.fromResult + | ToDist(Scale(#Logarithm, f)) => + dist + ->GenericDist.pointwiseCombinationFloat(~toPointSetFn, ~algebraicCombination=#Logarithm, ~f) + ->E.R2.fmap(r => Dist(r)) + ->OutputLocal.fromResult + | ToDist(Scale(#Power, f)) => + dist + ->GenericDist.pointwiseCombinationFloat(~toPointSetFn, ~algebraicCombination=#Power, ~f) + ->E.R2.fmap(r => Dist(r)) + ->OutputLocal.fromResult | ToDistCombination(Algebraic(_), _, #Float(_)) => GenDistError(NotYetImplemented) | ToDistCombination(Algebraic(strategy), arithmeticOperation, #Dist(t2)) => dist @@ -194,6 +204,12 @@ let rec run = (~env, functionCallInfo: functionCallInfo): outputType => { ->GenericDist.mixture(~scaleMultiplyFn=scaleMultiply, ~pointwiseAddFn=pointwiseAdd) ->E.R2.fmap(r => Dist(r)) ->OutputLocal.fromResult + | FromSamples(xs) => + xs + ->SampleSetDist.make + ->E.R2.errMap(x => DistributionTypes.SampleSetError(x)) + ->E.R2.fmap(x => x->DistributionTypes.SampleSet->Dist) + ->OutputLocal.fromResult } } @@ -234,6 +250,7 @@ module Constructors = { let isNormalized = (~env, dist) => C.isNormalized(dist)->run(~env)->toBoolR let toPointSet = (~env, dist) => C.toPointSet(dist)->run(~env)->toDistR let toSampleSet = (~env, dist, n) => C.toSampleSet(dist, n)->run(~env)->toDistR + let fromSamples = (~env, xs) => C.fromSamples(xs)->run(~env)->toDistR let truncate = (~env, dist, leftCutoff, rightCutoff) => C.truncate(dist, leftCutoff, rightCutoff)->run(~env)->toDistR let inspect = (~env, dist) => C.inspect(dist)->run(~env)->toDistR diff --git a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.resi b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.resi index d7f4f84e..77aa546b 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.resi +++ b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.resi @@ -64,6 +64,8 @@ module Constructors: { @genType let toSampleSet: (~env: env, genericDist, int) => result @genType + let fromSamples: (~env: env, SampleSetDist.t) => result + @genType let truncate: (~env: env, genericDist, option, option) => result @genType let inspect: (~env: env, genericDist) => result diff --git a/packages/squiggle-lang/src/rescript/Distributions/DistributionTypes.res b/packages/squiggle-lang/src/rescript/Distributions/DistributionTypes.res index 93f86798..0d413bf4 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/DistributionTypes.res +++ b/packages/squiggle-lang/src/rescript/Distributions/DistributionTypes.res @@ -11,7 +11,7 @@ type error = | NotYetImplemented | Unreachable | DistributionVerticalShiftIsInvalid - | TooFewSamples + | SampleSetError(SampleSetDist.sampleSetError) | ArgumentError(string) | OperationError(Operation.Error.t) | PointSetConversionError(SampleSetDist.pointsetConversionError) @@ -35,7 +35,8 @@ module Error = { | DistributionVerticalShiftIsInvalid => "Distribution Vertical Shift is Invalid" | ArgumentError(s) => `Argument Error ${s}` | LogarithmOfDistributionError(s) => `Logarithm of input error: ${s}` - | TooFewSamples => "Too Few Samples" + | SampleSetError(TooFewSamples) => "Too Few Samples" + | SampleSetError(NonNumericInput(err)) => `Found a non-number in input: ${err}` | OperationError(err) => Operation.Error.toString(err) | PointSetConversionError(err) => SampleSetDist.pointsetConversionErrorToString(err) | SparklineError(err) => PointSetTypes.sparklineErrorToString(err) @@ -47,10 +48,7 @@ module Error = { let resultStringToResultError: result<'a, string> => result<'a, error> = n => n->E.R2.errMap(r => r->fromString) - let sampleErrorToDistErr = (err: SampleSetDist.sampleSetError): error => - switch err { - | TooFewSamples => TooFewSamples - } + let sampleErrorToDistErr = (err: SampleSetDist.sampleSetError): error => SampleSetError(err) } @genType @@ -68,12 +66,19 @@ module DistributionOperation = { | #Pdf(float) | #Mean | #Sample + | #IntegralSum + ] + + type toScaleFn = [ + | #Power + | #Logarithm ] type toDist = | Normalize | ToPointSet | ToSampleSet(int) + | Scale(toScaleFn, float) | Truncate(option, option) | Inspect @@ -99,6 +104,7 @@ module DistributionOperation = { type genericFunctionCallInfo = | FromDist(fromDist, genericDist) | FromFloat(fromDist, float) + | FromSamples(array) | Mixture(array<(genericDist, float)>) let distCallToString = (distFunction: fromDist): string => @@ -113,6 +119,8 @@ module DistributionOperation = { | ToDist(ToSampleSet(r)) => `toSampleSet(${E.I.toString(r)})` | ToDist(Truncate(_, _)) => `truncate` | ToDist(Inspect) => `inspect` + | ToDist(Scale(#Power, r)) => `scalePower(${E.Float.toFixed(r)})` + | ToDist(Scale(#Logarithm, r)) => `scaleLog(${E.Float.toFixed(r)})` | ToString(ToString) => `toString` | ToString(ToSparkline(n)) => `toSparkline(${E.I.toString(n)})` | ToBool(IsNormalized) => `isNormalized` @@ -124,6 +132,7 @@ module DistributionOperation = { switch d { | FromDist(f, _) | FromFloat(f, _) => distCallToString(f) | Mixture(_) => `mixture` + | FromSamples(_) => `fromSamples` } } module Constructors = { @@ -140,8 +149,11 @@ module Constructors = { let isNormalized = (dist): t => FromDist(ToBool(IsNormalized), dist) let toPointSet = (dist): t => FromDist(ToDist(ToPointSet), dist) let toSampleSet = (dist, r): t => FromDist(ToDist(ToSampleSet(r)), dist) + let fromSamples = (xs): t => FromSamples(xs) let truncate = (dist, left, right): t => FromDist(ToDist(Truncate(left, right)), dist) let inspect = (dist): t => FromDist(ToDist(Inspect), dist) + let scalePower = (dist, n): t => FromDist(ToDist(Scale(#Power, n)), dist) + let scaleLogarithm = (dist, n): t => FromDist(ToDist(Scale(#Logarithm, n)), dist) let toString = (dist): t => FromDist(ToString(ToString), dist) let toSparkline = (dist, n): t => FromDist(ToString(ToSparkline(n)), dist) let algebraicAdd = (dist1, dist2: genericDist): t => FromDist( diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res index c19bdf7f..160ce640 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res @@ -62,26 +62,31 @@ let isNormalized = (t: t): bool => Js.Math.abs_float(integralEndY(t) -. 1.0) < 1 let toFloatOperation = ( t, ~toPointSetFn: toPointSetFn, - ~distToFloatOperation: Operation.distToFloatOperation, + ~distToFloatOperation: DistributionTypes.DistributionOperation.toFloat, ) => { - let trySymbolicSolution = switch (t: t) { - | Symbolic(r) => SymbolicDist.T.operate(distToFloatOperation, r)->E.R.toOption - | _ => None - } + switch distToFloatOperation { + | #IntegralSum => Ok(integralEndY(t)) + | (#Pdf(_) | #Cdf(_) | #Inv(_) | #Mean | #Sample) as op => { + let trySymbolicSolution = switch (t: t) { + | Symbolic(r) => SymbolicDist.T.operate(op, r)->E.R.toOption + | _ => None + } - let trySampleSetSolution = switch ((t: t), distToFloatOperation) { - | (SampleSet(sampleSet), #Mean) => SampleSetDist.mean(sampleSet)->Some - | (SampleSet(sampleSet), #Sample) => SampleSetDist.sample(sampleSet)->Some - | (SampleSet(sampleSet), #Inv(r)) => SampleSetDist.percentile(sampleSet, r)->Some - | _ => None - } + let trySampleSetSolution = switch ((t: t), distToFloatOperation) { + | (SampleSet(sampleSet), #Mean) => SampleSetDist.mean(sampleSet)->Some + | (SampleSet(sampleSet), #Sample) => SampleSetDist.sample(sampleSet)->Some + | (SampleSet(sampleSet), #Inv(r)) => SampleSetDist.percentile(sampleSet, r)->Some + | _ => None + } - switch trySymbolicSolution { - | Some(r) => Ok(r) - | None => - switch trySampleSetSolution { - | Some(r) => Ok(r) - | None => toPointSetFn(t)->E.R2.fmap(PointSetDist.operate(distToFloatOperation)) + switch trySymbolicSolution { + | Some(r) => Ok(r) + | None => + switch trySampleSetSolution { + | Some(r) => Ok(r) + | None => toPointSetFn(t)->E.R2.fmap(PointSetDist.operate(op)) + } + } } } } diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi index e91803e2..3d143edc 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi @@ -20,7 +20,7 @@ let isNormalized: t => bool let toFloatOperation: ( t, ~toPointSetFn: toPointSetFn, - ~distToFloatOperation: Operation.distToFloatOperation, + ~distToFloatOperation: DistributionTypes.DistributionOperation.toFloat, ) => result @genType diff --git a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Continuous.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Continuous.res index d4286387..105b5a05 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Continuous.res +++ b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Continuous.res @@ -156,8 +156,10 @@ let reduce = ( ~integralSumCachesFn: (float, float) => option=(_, _) => None, fn: (float, float) => result, continuousShapes, -): result => - continuousShapes |> E.A.R.foldM(combinePointwise(~integralSumCachesFn, fn), empty) +): result => { + let merge = combinePointwise(~integralSumCachesFn, fn) + continuousShapes |> E.A.R.foldM(merge, empty) +} let mapYResult = ( ~integralSumCacheFn=_ => None, diff --git a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Discrete.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Discrete.res index fdc921c6..1149df7e 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Discrete.res +++ b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Discrete.res @@ -34,9 +34,10 @@ let lastY = (t: t) => t |> getShape |> XYShape.T.lastY let combinePointwise = ( ~integralSumCachesFn=(_, _) => None, + fn, t1: PointSetTypes.discreteShape, t2: PointSetTypes.discreteShape, -): PointSetTypes.discreteShape => { +): result => { let combinedIntegralSum = Common.combineIntegralSums( integralSumCachesFn, t1.integralSumCache, @@ -49,16 +50,22 @@ let combinePointwise = ( make( ~integralSumCache=combinedIntegralSum, XYShape.PointwiseCombination.combine( - (a, b) => Ok(a +. b), + fn, XYShape.XtoY.discreteInterpolator, t1.xyShape, t2.xyShape, )->E.R.toExn("Addition operation should never fail", _), - ) + )->Ok } -let reduce = (~integralSumCachesFn=(_, _) => None, discreteShapes): PointSetTypes.discreteShape => - discreteShapes |> E.A.fold_left(combinePointwise(~integralSumCachesFn), empty) +let reduce = ( + ~integralSumCachesFn=(_, _) => None, + fn: (float, float) => result, + discreteShapes: array, +): result => { + let merge = combinePointwise(~integralSumCachesFn, fn) + discreteShapes |> E.A.R.foldM(merge, empty) +} let updateIntegralSumCache = (integralSumCache, t: t): t => { ...t, diff --git a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Mixed.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Mixed.res index 4ce2bdd6..98e7923a 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Mixed.res +++ b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Mixed.res @@ -316,7 +316,10 @@ let combinePointwise = ( t2: t, ): result => { let reducedDiscrete = - [t1, t2] |> E.A.fmap(toDiscrete) |> E.A.O.concatSomes |> Discrete.reduce(~integralSumCachesFn) + [t1, t2] + |> E.A.fmap(toDiscrete) + |> E.A.O.concatSomes + |> Discrete.reduce(~integralSumCachesFn, fn) let reducedContinuous = [t1, t2] @@ -335,11 +338,11 @@ let combinePointwise = ( t1.integralCache, t2.integralCache, ) - reducedContinuous->E.R2.fmap(continuous => + E.R.merge(reducedContinuous, reducedDiscrete)->E.R2.fmap(((continuous, discrete)) => make( ~integralSumCache=combinedIntegralSum, ~integralCache=combinedIntegral, - ~discrete=reducedDiscrete, + ~discrete, ~continuous, ) ) diff --git a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res index 12aa5477..00c900dc 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res @@ -84,7 +84,12 @@ let combinePointwise = ( m2, )->E.R2.fmap(x => PointSetTypes.Continuous(x)) | (Discrete(m1), Discrete(m2)) => - Ok(PointSetTypes.Discrete(Discrete.combinePointwise(~integralSumCachesFn, m1, m2))) + Discrete.combinePointwise( + ~integralSumCachesFn, + fn, + m1, + m2, + )->E.R2.fmap(x => PointSetTypes.Discrete(x)) | (m1, m2) => Mixed.combinePointwise( ~integralSumCachesFn, diff --git a/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist.res b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist.res index 14c66812..55b334c5 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist.res @@ -1,11 +1,12 @@ @genType module Error = { @genType - type sampleSetError = TooFewSamples + type sampleSetError = TooFewSamples | NonNumericInput(string) let sampleSetErrorToString = (err: sampleSetError): string => switch err { | TooFewSamples => "Too few samples when constructing sample set" + | NonNumericInput(err) => `Found a non-number in input: ${err}` } @genType diff --git a/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist_Bandwidth.res b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist_Bandwidth.res index aef659d1..29d48ad3 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist_Bandwidth.res +++ b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist_Bandwidth.res @@ -1,27 +1,30 @@ //The math here was taken from https://github.com/jasondavies/science.js/blob/master/src/stats/SampleSetDist_Bandwidth.js - +let {iqr_percentile, nrd0_lo_denominator, one, nrd0_coef, nrd_coef, nrd_fractionalPower} = module( + MagicNumbers.SampleSetBandwidth +) let len = x => E.A.length(x) |> float_of_int -let iqr = x => Jstat.percentile(x, 0.75, true) -. Jstat.percentile(x, 0.25, true) +let iqr = x => + Jstat.percentile(x, iqr_percentile, true) -. Jstat.percentile(x, 1.0 -. iqr_percentile, true) // Silverman, B. W. (1986) Density Estimation. London: Chapman and Hall. let nrd0 = x => { let hi = Js_math.sqrt(Jstat.variance(x)) - let lo = Js_math.minMany_float([hi, iqr(x) /. 1.34]) + let lo = Js_math.minMany_float([hi, iqr(x) /. nrd0_lo_denominator]) let e = Js_math.abs_float(x[1]) let lo' = switch (lo, hi, e) { | (lo, _, _) if !Js.Float.isNaN(lo) => lo | (_, hi, _) if !Js.Float.isNaN(hi) => hi | (_, _, e) if !Js.Float.isNaN(e) => e - | _ => 1.0 + | _ => one } - 0.9 *. lo' *. Js.Math.pow_float(~base=len(x), ~exp=-0.2) + nrd0_coef *. lo' *. Js.Math.pow_float(~base=len(x), ~exp=nrd_fractionalPower) } // Scott, D. W. (1992) Multivariate Density Estimation: Theory, Practice, and Visualization. Wiley. let nrd = x => { - let h = iqr(x) /. 1.34 - 1.06 *. + let h = iqr(x) /. nrd0_lo_denominator + nrd_coef *. Js.Math.min_float(Js.Math.sqrt(Jstat.variance(x)), h) *. - Js.Math.pow_float(~base=len(x), ~exp=-1.0 /. 5.0) + Js.Math.pow_float(~base=len(x), ~exp=nrd_fractionalPower) } diff --git a/packages/squiggle-lang/src/rescript/MagicNumbers.res b/packages/squiggle-lang/src/rescript/MagicNumbers.res index 124a44f4..0f059c03 100644 --- a/packages/squiggle-lang/src/rescript/MagicNumbers.res +++ b/packages/squiggle-lang/src/rescript/MagicNumbers.res @@ -35,3 +35,16 @@ module ToPointSet = { */ let minDiscreteToKeep = samples => max(20, E.A.length(samples) / 50) } + +module SampleSetBandwidth = { + // Silverman, B. W. (1986) Density Estimation. London: Chapman and Hall. + // Scott, D. W. (1992) Multivariate Density Estimation: Theory, Practice, and Visualization. Wiley. + let iqr_percentile = 0.75 + let iqr_percentile_complement = 1.0 -. iqr_percentile + let nrd0_lo_denominator = 1.34 + let one = 1.0 + let nrd0_coef = 0.9 + + let nrd_coef = 1.06 + let nrd_fractionalPower = -0.2 +} diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_ExpressionBuilder.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_ExpressionBuilder.res index ec3a0214..989d2810 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_ExpressionBuilder.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_ExpressionBuilder.res @@ -26,10 +26,10 @@ let eFunction = (fName: string, lispArgs: list): expression => { } let eLambda = (parameters: array, context, expr) => - BExpressionValue.EvLambda( - parameters, - context, - expr->castExpressionToInternalCode, + BExpressionValue.EvLambda({ + parameters: parameters, + context: context, + body: expr->castExpressionToInternalCode} )->BExpressionT.EValue let eNumber = aNumber => aNumber->BExpressionValue.EvNumber->BExpressionT.EValue diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Lambda.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Lambda.res index a2d795c0..675e3bc3 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Lambda.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Lambda.res @@ -30,6 +30,6 @@ let applyParametersToLambda = ( reducer(newExpression, bindings, environment) } -let doLambdaCall = ((parameters, context, internal), args, environment, reducer) => { - applyParametersToLambda(internal, parameters, args, context, environment, reducer) +let doLambdaCall = (lambdaValue: ExpressionValue.lambdaValue, args, environment, reducer) => { + applyParametersToLambda(lambdaValue.body, lambdaValue.parameters, args, lambdaValue.context, environment, reducer) } diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res index 60300c82..4d6911af 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res @@ -15,15 +15,19 @@ type rec expressionValue = | EvBool(bool) | EvCall(string) // External function call | EvDistribution(DistributionTypes.genericDist) - | EvLambda((array, record, internalCode)) + | EvLambda(lambdaValue) | EvNumber(float) | EvRecord(record) | EvString(string) | EvSymbol(string) and record = Js.Dict.t +and externalBindings = record +and lambdaValue = { + parameters: array, + context: externalBindings, + body: internalCode, +} -@genType -type externalBindings = record @genType let defaultExternalBindings: externalBindings = Js.Dict.empty() @@ -41,8 +45,8 @@ let rec toString = aValue => } | EvBool(aBool) => Js.String.make(aBool) | EvCall(fName) => `:${fName}` - | EvLambda((parameters, _context, _internalCode)) => - `lambda(${Js.Array2.toString(parameters)}=>internal)` + | EvLambda(lambdaValue) => + `lambda(${Js.Array2.toString(lambdaValue.parameters)}=>internal code)` | EvNumber(aNumber) => Js.String.make(aNumber) | EvString(aString) => `'${aString}'` | EvSymbol(aString) => `:${aString}` @@ -65,7 +69,7 @@ let toStringWithType = aValue => | EvBool(_) => `Bool::${toString(aValue)}` | EvCall(_) => `Call::${toString(aValue)}` | EvDistribution(_) => `Distribution::${toString(aValue)}` - | EvLambda((_parameters, _context, _internalCode)) => `Lambda::${toString(aValue)}` + | EvLambda(_) => `Lambda::${toString(aValue)}` | EvNumber(_) => `Number::${toString(aValue)}` | EvRecord(_) => `Record::${toString(aValue)}` | EvString(_) => `String::${toString(aValue)}` diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res index d5926d0f..4615fa44 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res @@ -130,6 +130,7 @@ module Helpers = { | Error(err) => GenDistError(ArgumentError(err)) } } + | Some(EvNumber(_)) | Some(EvDistribution(_)) => switch parseDistributionArray(args) { | Ok(distributions) => mixtureWithDefaultWeights(distributions) @@ -194,6 +195,7 @@ let dispatchToGenericOutput = (call: ExpressionValue.functionCall, _environment) ->SymbolicConstructors.symbolicResultToOutput | ("sample", [EvDistribution(dist)]) => Helpers.toFloatFn(#Sample, dist) | ("mean", [EvDistribution(dist)]) => Helpers.toFloatFn(#Mean, dist) + | ("integralSum", [EvDistribution(dist)]) => Helpers.toFloatFn(#IntegralSum, dist) | ("toString", [EvDistribution(dist)]) => Helpers.toStringFn(ToString, dist) | ("toSparkline", [EvDistribution(dist)]) => Helpers.toStringFn(ToSparkline(20), dist) | ("toSparkline", [EvDistribution(dist), EvNumber(n)]) => @@ -209,6 +211,15 @@ let dispatchToGenericOutput = (call: ExpressionValue.functionCall, _environment) | ("normalize", [EvDistribution(dist)]) => Helpers.toDistFn(Normalize, dist) | ("isNormalized", [EvDistribution(dist)]) => Helpers.toBoolFn(IsNormalized, dist) | ("toPointSet", [EvDistribution(dist)]) => Helpers.toDistFn(ToPointSet, dist) + | ("scaleLog", [EvDistribution(dist)]) => + Helpers.toDistFn(Scale(#Logarithm, MagicNumbers.Math.e), dist) + | ("scaleLog10", [EvDistribution(dist)]) => Helpers.toDistFn(Scale(#Logarithm, 10.0), dist) + | ("scaleLog", [EvDistribution(dist), EvNumber(float)]) => + Helpers.toDistFn(Scale(#Logarithm, float), dist) + | ("scalePow", [EvDistribution(dist), EvNumber(float)]) => + Helpers.toDistFn(Scale(#Power, float), dist) + | ("scaleExp", [EvDistribution(dist)]) => + Helpers.toDistFn(Scale(#Power, MagicNumbers.Math.e), dist) | ("cdf", [EvDistribution(dist), EvNumber(float)]) => Helpers.toFloatFn(#Cdf(float), dist) | ("pdf", [EvDistribution(dist), EvNumber(float)]) => Helpers.toFloatFn(#Pdf(float), dist) | ("inv", [EvDistribution(dist), EvNumber(float)]) => Helpers.toFloatFn(#Inv(float), dist) @@ -216,6 +227,14 @@ let dispatchToGenericOutput = (call: ExpressionValue.functionCall, _environment) Helpers.toDistFn(ToSampleSet(Belt.Int.fromFloat(float)), dist) | ("toSampleSet", [EvDistribution(dist)]) => Helpers.toDistFn(ToSampleSet(MagicNumbers.Environment.defaultSampleCount), dist) + | ("fromSamples", [EvArray(inputArray)]) => { + let _wrapInputErrors = x => SampleSetDist.NonNumericInput(x) + let parsedArray = Helpers.parseNumberArray(inputArray)->E.R2.errMap(_wrapInputErrors) + switch parsedArray { + | Ok(array) => runGenericOperation(FromSamples(array)) + | Error(e) => GenDistError(SampleSetError(e)) + }->Some + } | ("inspect", [EvDistribution(dist)]) => Helpers.toDistFn(Inspect, dist) | ("truncateLeft", [EvDistribution(dist), EvNumber(float)]) => Helpers.toDistFn(Truncate(Some(float), None), dist) diff --git a/packages/squiggle-lang/src/rescript/Utility/E.res b/packages/squiggle-lang/src/rescript/Utility/E.res index f5b38be7..472c32f7 100644 --- a/packages/squiggle-lang/src/rescript/Utility/E.res +++ b/packages/squiggle-lang/src/rescript/Utility/E.res @@ -289,6 +289,13 @@ module R = { | Ok(r) => r->Ok | Error(x) => x->f->Error } + + //I'm not sure what to call this. + let unify = (a: result<'a, 'b>, c: 'b => 'a): 'a => + switch a { + | Ok(x) => x + | Error(x) => c(x) + } } module R2 = { @@ -307,6 +314,8 @@ module R2 = { | Ok(x) => x->Ok | Error(x) => x->f->Error } + + let toExn = (a, b) => R.toExn(b, a) } let safe_fn_of_string = (fn, s: string): option<'a> => diff --git a/packages/website/docs/Features/Functions.mdx b/packages/website/docs/Features/Functions.mdx index e37ea315..1de7514b 100644 --- a/packages/website/docs/Features/Functions.mdx +++ b/packages/website/docs/Features/Functions.mdx @@ -98,6 +98,19 @@ bound `a`, mode `b` and upper bound `c`. Squiggle, when the context is right, automatically casts a float to a constant distribution. +## `fromSamples` + +The last distribution constructor takes an array of samples and constructs a sample set distribution. + + + +#### Validity + +For `fromSamples(xs)`, + +- `xs.length > 5` +- Strictly every element of `xs` must be a number. + ## Operating on distributions Here are the ways we combine distributions. @@ -315,6 +328,16 @@ Or `PointSet` format +### `toSampleSet` has two signatures + +Above, we saw the unary `toSampleSet`, which uses an internal hardcoded number of samples. If you'd like to provide the number of samples, it has a binary signature as well (floored) + + + +#### Validity + +- Second argument to `toSampleSet` must be a number. + ## Normalization Some distribution operations (like horizontal shift) return an unnormalized distriibution. @@ -333,18 +356,6 @@ We provide a predicate `isNormalized`, for when we have simple control flow - 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. diff --git a/yarn.lock b/yarn.lock index 3597fea6..89928253 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6498,7 +6498,7 @@ coa@^2.0.2: chalk "^2.4.1" q "^1.1.2" -codecov@3.8.3: +codecov@^3.8.3: version "3.8.3" resolved "https://registry.yarnpkg.com/codecov/-/codecov-3.8.3.tgz#9c3e364b8a700c597346ae98418d09880a3fdbe7" integrity sha512-Y8Hw+V3HgR7V71xWH2vQ9lyS358CbGCldWlJFR0JirqoGtOoas3R3/OclRTvgUYFK29mmJICDPauVKmpqbwhOA== @@ -8607,7 +8607,7 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" -fast-check@2.25.0, fast-check@^2.17.0: +fast-check@^2.17.0, fast-check@^2.25.0: version "2.25.0" resolved "https://registry.yarnpkg.com/fast-check/-/fast-check-2.25.0.tgz#5146601851bf3be0953bd17eb2b7d547936c6561" integrity sha512-wRUT2KD2lAmT75WNIJIHECawoUUMHM0I5jrlLXGtGeqmPL8jl/EldUDjY1VCp6fDY8yflyfUeIOsOBrIbIiArg== @@ -11627,7 +11627,7 @@ lodash.uniq@4.5.0, lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -lodash@4.17.21, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.4, lodash@^4.7.0: +lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.4, lodash@^4.7.0: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -11751,7 +11751,7 @@ markdown-to-jsx@^7.1.3: resolved "https://registry.yarnpkg.com/markdown-to-jsx/-/markdown-to-jsx-7.1.7.tgz#a5f22102fb12241c8cea1ca6a4050bb76b23a25d" integrity sha512-VI3TyyHlGkO8uFle0IOibzpO1c1iJDcXcS/zBrQrXQQvJ2tpdwVzVZ7XdKsyRz1NdRmre4dqQkMZzUHaKIG/1w== -mathjs@10.5.0: +mathjs@^10.5.0: version "10.5.0" resolved "https://registry.yarnpkg.com/mathjs/-/mathjs-10.5.0.tgz#f81d0518fe7b4b2a0b85e1125b8ecfc364fb0292" integrity sha512-gRnSY9psN9zgiB2QV9F4XbuX5hwjxY5Ou7qoTFWDbn2vZ3UEs+sjfK/SRg2WP30TNfZWpwlGdp8H1knFJnpFdA== @@ -12120,7 +12120,7 @@ mkdirp@^1.0.3, mkdirp@^1.0.4: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -moduleserve@0.9.1: +moduleserve@^0.9.1: version "0.9.1" resolved "https://registry.yarnpkg.com/moduleserve/-/moduleserve-0.9.1.tgz#11bad4337ea248d7eaf10d2c7f8649a8c3b9c1f8" integrity sha512-WF2BeGnM2Ko7bdICgJO+Ibu+ZD33ExJHzOzTDsCUzfZnvnFfheEIYBTWyIqSRU0tXh4UTQ1krDOCglFTJPBMow== @@ -14439,7 +14439,7 @@ react-ace@10.0.0: lodash.isequal "^4.5.0" prop-types "^15.7.2" -react-ace@10.1.0: +react-ace@^10.1.0: version "10.1.0" resolved "https://registry.yarnpkg.com/react-ace/-/react-ace-10.1.0.tgz#d348eac2b16475231779070b6cd16768deed565f" integrity sha512-VkvUjZNhdYTuKOKQpMIZi7uzZZVgzCjM7cLYu6F64V0mejY8a2XTyPUIMszC6A4trbeMIHbK5fYFcT/wkP/8VA== @@ -14693,7 +14693,7 @@ react-router@6.3.0, react-router@^6.0.0: dependencies: history "^5.2.0" -react-scripts@5.0.1: +react-scripts@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/react-scripts/-/react-scripts-5.0.1.tgz#6285dbd65a8ba6e49ca8d651ce30645a6d980003" integrity sha512-8VAmEm/ZAwQzJ+GOMLbBsTdDKOpuZh7RPs0UymvBR2vRk4iZWCskjbFnxqjrzoIvlNNRZ3QJFx6/qDSi6zSnaQ==