From e42ac0b58d14b68624596415f1652a02096cccad Mon Sep 17 00:00:00 2001 From: Quinn Dougherty Date: Wed, 6 Apr 2022 16:02:32 -0400 Subject: [PATCH 01/41] renamed `t` to `T` --- .../DistributionOperation__Test.res} | 0 .../__tests__/{Lodash__test.res => Lodash__Test.res} | 0 ...patch_BuiltIn_test.res => Reducer_Dispatch_BuiltIn_Test.res} | 0 ...{Reducer_MathJsEval_test.res => Reducer_MathJsEval_Test.res} | 0 ...educer_MathJsParse_test.res => Reducer_MathJsParse_Test.res} | 0 .../__tests__/Reducer/{Reducer_test.res => Reducer_Test.res} | 0 ...ribution_test.res => ReducerInterface_Distribution_Test.res} | 0 ...Value_test.res => ReducerInterface_ExpressionValue_Test.res} | 0 .../__tests__/{Samples__test.res => Samples__Test.res} | 0 .../__tests__/{Symbolic_test.res => Symbolic_Test.res} | 0 packages/squiggle-lang/package.json | 2 +- 11 files changed, 1 insertion(+), 1 deletion(-) rename packages/squiggle-lang/__tests__/{GenericDist/GenericOperation__Test.res => Distributions/DistributionOperation__Test.res} (100%) rename packages/squiggle-lang/__tests__/{Lodash__test.res => Lodash__Test.res} (100%) rename packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/{Reducer_Dispatch_BuiltIn_test.res => Reducer_Dispatch_BuiltIn_Test.res} (100%) rename packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/{Reducer_MathJsEval_test.res => Reducer_MathJsEval_Test.res} (100%) rename packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/{Reducer_MathJsParse_test.res => Reducer_MathJsParse_Test.res} (100%) rename packages/squiggle-lang/__tests__/Reducer/{Reducer_test.res => Reducer_Test.res} (100%) rename packages/squiggle-lang/__tests__/ReducerInterface/{ReducerInterface_Distribution_test.res => ReducerInterface_Distribution_Test.res} (100%) rename packages/squiggle-lang/__tests__/ReducerInterface/{ReducerInterface_ExpressionValue_test.res => ReducerInterface_ExpressionValue_Test.res} (100%) rename packages/squiggle-lang/__tests__/{Samples__test.res => Samples__Test.res} (100%) rename packages/squiggle-lang/__tests__/{Symbolic_test.res => Symbolic_Test.res} (100%) diff --git a/packages/squiggle-lang/__tests__/GenericDist/GenericOperation__Test.res b/packages/squiggle-lang/__tests__/Distributions/DistributionOperation__Test.res similarity index 100% rename from packages/squiggle-lang/__tests__/GenericDist/GenericOperation__Test.res rename to packages/squiggle-lang/__tests__/Distributions/DistributionOperation__Test.res diff --git a/packages/squiggle-lang/__tests__/Lodash__test.res b/packages/squiggle-lang/__tests__/Lodash__Test.res similarity index 100% rename from packages/squiggle-lang/__tests__/Lodash__test.res rename to packages/squiggle-lang/__tests__/Lodash__Test.res diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn_Test.res similarity index 100% rename from packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn_test.res rename to packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn_Test.res diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsEval_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsEval_Test.res similarity index 100% rename from packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsEval_test.res rename to packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsEval_Test.res diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_Test.res similarity index 100% rename from packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res rename to packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_Test.res diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Test.res similarity index 100% rename from packages/squiggle-lang/__tests__/Reducer/Reducer_test.res rename to packages/squiggle-lang/__tests__/Reducer/Reducer_Test.res diff --git a/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_test.res b/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_Test.res similarity index 100% rename from packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_test.res rename to packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_Test.res diff --git a/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_ExpressionValue_test.res b/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_ExpressionValue_Test.res similarity index 100% rename from packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_ExpressionValue_test.res rename to packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_ExpressionValue_Test.res diff --git a/packages/squiggle-lang/__tests__/Samples__test.res b/packages/squiggle-lang/__tests__/Samples__Test.res similarity index 100% rename from packages/squiggle-lang/__tests__/Samples__test.res rename to packages/squiggle-lang/__tests__/Samples__Test.res diff --git a/packages/squiggle-lang/__tests__/Symbolic_test.res b/packages/squiggle-lang/__tests__/Symbolic_Test.res similarity index 100% rename from packages/squiggle-lang/__tests__/Symbolic_test.res rename to packages/squiggle-lang/__tests__/Symbolic_Test.res diff --git a/packages/squiggle-lang/package.json b/packages/squiggle-lang/package.json index 459c3d2b..03983cd2 100644 --- a/packages/squiggle-lang/package.json +++ b/packages/squiggle-lang/package.json @@ -10,7 +10,7 @@ "test:reducer": "jest --testPathPattern '.*__tests__/Reducer.*'", "test": "jest", "test:watch": "jest --watchAll", - "coverage": "rm -f *.coverage; yarn clean; BISECT_ENABLE=yes yarn build; yarn test; ./node_modules/.bin/bisect-ppx-report html", + "coverage": "rm -f *.coverage; yarn clean; BISECT_ENABLE=yes yarn build; yarn test; bisect-ppx-report html", "all": "yarn build && yarn bundle && yarn test" }, "keywords": [ From 0a5a8a51982cb7dc5c5fda2f3228e49c4fd0cd94 Mon Sep 17 00:00:00 2001 From: Quinn Dougherty Date: Wed, 6 Apr 2022 18:57:51 -0400 Subject: [PATCH 02/41] property test framework installed but not used; describe(means) section of unit tests filled out --- packages/squiggle-lang/README.md | 3 + .../DistributionOperation__Test.res | 97 +++++++++++++++++-- packages/squiggle-lang/bsconfig.json | 3 + packages/squiggle-lang/package.json | 1 + .../SymbolicDist/SymbolicDist.res | 8 +- yarn.lock | 19 ++++ 6 files changed, 121 insertions(+), 10 deletions(-) diff --git a/packages/squiggle-lang/README.md b/packages/squiggle-lang/README.md index a7d0d5d0..87bc76fe 100644 --- a/packages/squiggle-lang/README.md +++ b/packages/squiggle-lang/README.md @@ -13,6 +13,9 @@ Other: yarn start # listens to files and recompiles at every mutation yarn test yarn test:watch # keeps an active session and runs all tests at every mutation + +# where o := open in osx and o := xdg-open in linux, +yarn coverage; o _coverage/index.html # produces coverage report and opens it in browser ``` # TODO: clean up this README.md diff --git a/packages/squiggle-lang/__tests__/Distributions/DistributionOperation__Test.res b/packages/squiggle-lang/__tests__/Distributions/DistributionOperation__Test.res index dc456865..d0135cf1 100644 --- a/packages/squiggle-lang/__tests__/Distributions/DistributionOperation__Test.res +++ b/packages/squiggle-lang/__tests__/Distributions/DistributionOperation__Test.res @@ -1,14 +1,18 @@ open Jest open Expect +open FastCheck +// open Arbitrary +open Property.Sync let env: DistributionOperation.env = { sampleCount: 100, xyPointLength: 100, } -let normalDist5: GenericDist_Types.genericDist = Symbolic(#Normal({mean: 5.0, stdev: 2.0})) -let normalDist10: GenericDist_Types.genericDist = Symbolic(#Normal({mean: 10.0, stdev: 2.0})) -let normalDist20: GenericDist_Types.genericDist = Symbolic(#Normal({mean: 20.0, stdev: 2.0})) +let mkNormal = (mean, stdev) => GenericDist_Types.Symbolic(#Normal({mean: mean, stdev: stdev})) +let normalDist5: GenericDist_Types.genericDist = mkNormal(5.0, 2.0) +let normalDist10: GenericDist_Types.genericDist = mkNormal(10.0, 2.0) +let normalDist20: GenericDist_Types.genericDist = mkNormal(20.0, 2.0) let uniformDist: GenericDist_Types.genericDist = Symbolic(#Uniform({low: 9.0, high: 10.0})) let {toFloat, toDist, toString, toError} = module(DistributionOperation.Output) @@ -19,18 +23,99 @@ let outputMap = fmap(~env) let toExt: option<'a> => 'a = E.O.toExt( "Should be impossible to reach (This error is in test file)", ) +let unpackFloat = x => x -> toFloat -> toExt describe("normalize", () => { test("has no impact on normal dist", () => { let result = run(FromDist(ToDist(Normalize), normalDist5)) expect(result)->toEqual(Dist(normalDist5)) }) + + // Test is vapid while I figure out how to get jest to work with fast-check + // monitor situation here maybe https://github.com/TheSpyder/rescript-fast-check/issues/8 ? + test("all normals are already normalized", () => { + expect(assert_( + property2( + Arbitrary.double(()), + Arbitrary.double(()), + (mean, stdev) => { + // open! Expect.Operators + open GenericDist_Types.Operation + run(FromDist(ToDist(Normalize), mkNormal(mean, stdev))) == DistributionOperation.Dist(mkNormal(mean, stdev)) + } + ) + )) -> toEqual(()) + }) }) describe("mean", () => { - test("for a normal distribution", () => { - let result = DistributionOperation.run(~env, FromDist(ToFloat(#Mean), normalDist5)) - expect(result)->toEqual(Float(5.0)) + test("of a normal distribution", () => { // should be property + run(FromDist(ToFloat(#Mean), normalDist5)) -> unpackFloat -> expect -> toBeCloseTo(5.0) + }) + + test("of an exponential distribution at a small rate", () => { // should be property + let rate = 1e-7 + let theMean = run(FromDist(ToFloat(#Mean), GenericDist_Types.Symbolic(#Exponential({rate: rate})))) + theMean -> unpackFloat -> expect -> toBeCloseTo(1.0 /. rate) // https://en.wikipedia.org/wiki/Exponential_distribution#Mean,_variance,_moments,_and_median + }) + + test("of an exponential distribution at a larger rate", () => { + let rate = 10.0 + let theMean = run(FromDist(ToFloat(#Mean), GenericDist_Types.Symbolic(#Exponential({rate: rate})))) + theMean -> unpackFloat -> expect -> toBeCloseTo(1.0 /. rate) // https://en.wikipedia.org/wiki/Exponential_distribution#Mean,_variance,_moments,_and_median + }) + +// test("of a cauchy distribution", () => { +// let result = run(FromDist(ToFloat(#Mean), GenericDist_Types.Symbolic(#Cauchy({local: 1.0, scale: 1.0})))) +// expect(result) -> toEqual(Error("Cauchy distributions may have no mean value.")) +// }) + + test("of a triangular distribution", () => { // should be property + let theMean = run(FromDist( + ToFloat(#Mean), + GenericDist_Types.Symbolic(#Triangular({low: - 5.0, medium: 1e-3, high: 10.0})) + )) + theMean -> unpackFloat -> expect -> toBeCloseTo((-5.0 +. 1e-3 +. 10.0) /. 3.0) // https://www.statology.org/triangular-distribution/ + }) + + test("of a beta distribution with alpha much smaller than beta", () => { // should be property + let theMean = run(FromDist( + ToFloat(#Mean), + GenericDist_Types.Symbolic(#Beta({alpha: 2e-4, beta: 64.0})) + )) + theMean -> unpackFloat -> expect -> toBeCloseTo(1.0 /. (1.0 +. (64.0 /. 2e-4))) // https://en.wikipedia.org/wiki/Beta_distribution#Mean + }) + + test("of a beta distribution with alpha much larger than beta", () => { // should be property + let theMean = run(FromDist( + ToFloat(#Mean), + GenericDist_Types.Symbolic(#Beta({alpha: 128.0, beta: 1.0})) + )) + theMean -> unpackFloat -> expect -> toBeCloseTo(1.0 /. (1.0 +. (1.0 /. 128.0))) // https://en.wikipedia.org/wiki/Beta_distribution#Mean + }) + + test("of a lognormal", () => { // should be property + let theMean = run(FromDist( + ToFloat(#Mean), + GenericDist_Types.Symbolic(#Lognormal({mu: 2.0, sigma: 4.0})) + )) + theMean -> unpackFloat -> expect -> toBeCloseTo(Js.Math.exp(2.0 +. 4.0 ** 2.0 /. 2.0 )) // https://brilliant.org/wiki/log-normal-distribution/ + }) + + test("of a uniform", () => { + let theMean = run(FromDist( + ToFloat(#Mean), + GenericDist_Types.Symbolic(#Uniform({low: 1e-5, high: 12.345})) + )) + theMean -> unpackFloat -> expect -> toBeCloseTo((1e-5 +. 12.345) /. 2.0) // https://en.wikipedia.org/wiki/Continuous_uniform_distribution#Moments + }) + + test("of a float", () => { + let theMean = run(FromDist( + ToFloat(#Mean), + GenericDist_Types.Symbolic(#Float(7.7)) + )) + theMean -> unpackFloat -> expect -> toBeCloseTo(7.7) }) }) diff --git a/packages/squiggle-lang/bsconfig.json b/packages/squiggle-lang/bsconfig.json index 4f38e124..9bd15e11 100644 --- a/packages/squiggle-lang/bsconfig.json +++ b/packages/squiggle-lang/bsconfig.json @@ -30,6 +30,9 @@ "rationale", "bisect_ppx" ], + "bs-dev-dependencies": [ + "rescript-fast-check" + ], "gentypeconfig": { "language": "typescript", "module": "commonjs", diff --git a/packages/squiggle-lang/package.json b/packages/squiggle-lang/package.json index 03983cd2..92554dd9 100644 --- a/packages/squiggle-lang/package.json +++ b/packages/squiggle-lang/package.json @@ -35,6 +35,7 @@ "docsify": "^4.12.2", "gentype": "^4.3.0", "jest": "^27.5.1", + "rescript-fast-check": "^1.1.1", "moduleserve": "0.9.1", "ts-jest": "^27.1.4", "ts-loader": "^9.2.8", diff --git a/packages/squiggle-lang/src/rescript/Distributions/SymbolicDist/SymbolicDist.res b/packages/squiggle-lang/src/rescript/Distributions/SymbolicDist/SymbolicDist.res index cd4132b3..626b8099 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/SymbolicDist/SymbolicDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/SymbolicDist/SymbolicDist.res @@ -55,7 +55,7 @@ module Exponential = { rate: rate, }), ) - : Error("Exponential distributions mean must be larger than 0") + : Error("Exponential distributions rate must be larger than 0.") let pdf = (x, t: t) => Jstat.Exponential.pdf(x, t.rate) let cdf = (x, t: t) => Jstat.Exponential.cdf(x, t.rate) let inv = (p, t: t) => Jstat.Exponential.inv(p, t.rate) @@ -71,7 +71,7 @@ module Cauchy = { 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) let sample = (t: t) => Jstat.Cauchy.sample(t.local, t.scale) - let mean = (_: t) => Error("Cauchy distributions have no mean value.") + let mean = (_: t) => Error("Cauchy distributions may have no mean value.") let toString = ({local, scale}: t) => j`Cauchy($local, $scale)` } @@ -80,8 +80,8 @@ module Triangular = { let make = (low, medium, high): result => low < medium && medium < high ? Ok(#Triangular({low: low, medium: medium, high: high})) - : Error("Triangular values must be increasing order") - let pdf = (x, t: t) => Jstat.Triangular.pdf(x, t.low, t.high, t.medium) + : Error("Triangular values must be increasing order.") + let pdf = (x, t: t) => Jstat.Triangular.pdf(x, t.low, t.high, t.medium) // not obvious in jstat docs that high comes before medium? let cdf = (x, t: t) => Jstat.Triangular.cdf(x, t.low, t.high, t.medium) let inv = (p, t: t) => Jstat.Triangular.inv(p, t.low, t.high, t.medium) let sample = (t: t) => Jstat.Triangular.sample(t.low, t.high, t.medium) diff --git a/yarn.lock b/yarn.lock index 6d0a7619..8a0e9676 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8392,6 +8392,13 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" +fast-check@^2.17.0: + version "2.24.0" + resolved "https://registry.yarnpkg.com/fast-check/-/fast-check-2.24.0.tgz#39f85586862108a4de6394c5196ebcf8b76b6c8b" + integrity sha512-iNXbN90lbabaCUfnW5jyXYPwMJLFYl09eJDkXA9ZoidFlBK63gNRvcKxv+8D1OJ1kIYjwBef4bO/K3qesUeWLQ== + dependencies: + pure-rand "^5.0.1" + fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3, fast-deep-equal@~3.1.3: version "3.1.3" resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" @@ -13524,6 +13531,11 @@ pure-color@^1.2.0: resolved "https://registry.yarnpkg.com/pure-color/-/pure-color-1.3.0.tgz#1fe064fb0ac851f0de61320a8bf796836422f33e" integrity sha1-H+Bk+wrIUfDeYTIKi/eWg2Qi8z4= +pure-rand@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-5.0.1.tgz#97a287b4b4960b2a3448c0932bf28f2405cac51d" + integrity sha512-ksWccjmXOHU2gJBnH0cK1lSYdvSZ0zLoCMSz/nTGh6hDvCSgcRxDyIcOBD6KNxFz3xhMPm/T267Tbe2JRymKEQ== + q@^1.1.2: version "1.5.1" resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" @@ -14712,6 +14724,13 @@ requires-port@^1.0.0: resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= +rescript-fast-check@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/rescript-fast-check/-/rescript-fast-check-1.1.1.tgz#ef153cb01254b2f01a738faf85b73327d423d5e1" + integrity sha512-wxeW0TsL/prkRvEYGbhEiLaLKmYJaECyDcKEWh65hDqP2i76lARzVW3QmYujSYK4OnjAC70dln3X6UC/2m2Huw== + dependencies: + fast-check "^2.17.0" + rescript@^9.1.4: version "9.1.4" resolved "https://registry.npmjs.org/rescript/-/rescript-9.1.4.tgz" From 6b15698d4e135937f794b168efcbe4178c8ce442 Mon Sep 17 00:00:00 2001 From: Quinn Dougherty Date: Wed, 6 Apr 2022 19:38:54 -0400 Subject: [PATCH 03/41] replaced `*__Test.res` with `*_test.res` --- .../__tests__/{Bandwidth__Test.res => Bandwidth_test.res} | 0 ...ibutionOperation__Test.res => DistributionOperation__test.res} | 0 .../squiggle-lang/__tests__/{Lodash__Test.res => Lodash_test.res} | 0 ...ispatch_BuiltIn_Test.res => Reducer_Dispatch_BuiltIn_test.res} | 0 .../{Reducer_MathJsEval_Test.res => Reducer_MathJsEval_test.res} | 0 ...{Reducer_MathJsParse_Test.res => Reducer_MathJsParse_test.res} | 0 .../__tests__/Reducer/{Reducer_Test.res => Reducer_test.res} | 0 ...stribution_Test.res => ReducerInterface_Distribution_test.res} | 0 ...onValue_Test.res => ReducerInterface_ExpressionValue_test.res} | 0 .../__tests__/{Samples__Test.res => Samples_test.res} | 0 .../__tests__/{Symbolic_Test.res => Symbolic_test.res} | 0 .../__tests__/{XYShape__Test.res => XYShape_test.res} | 0 12 files changed, 0 insertions(+), 0 deletions(-) rename packages/squiggle-lang/__tests__/{Bandwidth__Test.res => Bandwidth_test.res} (100%) rename packages/squiggle-lang/__tests__/Distributions/{DistributionOperation__Test.res => DistributionOperation__test.res} (100%) rename packages/squiggle-lang/__tests__/{Lodash__Test.res => Lodash_test.res} (100%) rename packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/{Reducer_Dispatch_BuiltIn_Test.res => Reducer_Dispatch_BuiltIn_test.res} (100%) rename packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/{Reducer_MathJsEval_Test.res => Reducer_MathJsEval_test.res} (100%) rename packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/{Reducer_MathJsParse_Test.res => Reducer_MathJsParse_test.res} (100%) rename packages/squiggle-lang/__tests__/Reducer/{Reducer_Test.res => Reducer_test.res} (100%) rename packages/squiggle-lang/__tests__/ReducerInterface/{ReducerInterface_Distribution_Test.res => ReducerInterface_Distribution_test.res} (100%) rename packages/squiggle-lang/__tests__/ReducerInterface/{ReducerInterface_ExpressionValue_Test.res => ReducerInterface_ExpressionValue_test.res} (100%) rename packages/squiggle-lang/__tests__/{Samples__Test.res => Samples_test.res} (100%) rename packages/squiggle-lang/__tests__/{Symbolic_Test.res => Symbolic_test.res} (100%) rename packages/squiggle-lang/__tests__/{XYShape__Test.res => XYShape_test.res} (100%) diff --git a/packages/squiggle-lang/__tests__/Bandwidth__Test.res b/packages/squiggle-lang/__tests__/Bandwidth_test.res similarity index 100% rename from packages/squiggle-lang/__tests__/Bandwidth__Test.res rename to packages/squiggle-lang/__tests__/Bandwidth_test.res diff --git a/packages/squiggle-lang/__tests__/Distributions/DistributionOperation__Test.res b/packages/squiggle-lang/__tests__/Distributions/DistributionOperation__test.res similarity index 100% rename from packages/squiggle-lang/__tests__/Distributions/DistributionOperation__Test.res rename to packages/squiggle-lang/__tests__/Distributions/DistributionOperation__test.res diff --git a/packages/squiggle-lang/__tests__/Lodash__Test.res b/packages/squiggle-lang/__tests__/Lodash_test.res similarity index 100% rename from packages/squiggle-lang/__tests__/Lodash__Test.res rename to packages/squiggle-lang/__tests__/Lodash_test.res diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn_Test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn_test.res similarity index 100% rename from packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn_Test.res rename to packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn_test.res diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsEval_Test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsEval_test.res similarity index 100% rename from packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsEval_Test.res rename to packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsEval_test.res diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_Test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res similarity index 100% rename from packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_Test.res rename to packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res similarity index 100% rename from packages/squiggle-lang/__tests__/Reducer/Reducer_Test.res rename to packages/squiggle-lang/__tests__/Reducer/Reducer_test.res diff --git a/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_Test.res b/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_test.res similarity index 100% rename from packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_Test.res rename to packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_test.res diff --git a/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_ExpressionValue_Test.res b/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_ExpressionValue_test.res similarity index 100% rename from packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_ExpressionValue_Test.res rename to packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_ExpressionValue_test.res diff --git a/packages/squiggle-lang/__tests__/Samples__Test.res b/packages/squiggle-lang/__tests__/Samples_test.res similarity index 100% rename from packages/squiggle-lang/__tests__/Samples__Test.res rename to packages/squiggle-lang/__tests__/Samples_test.res diff --git a/packages/squiggle-lang/__tests__/Symbolic_Test.res b/packages/squiggle-lang/__tests__/Symbolic_test.res similarity index 100% rename from packages/squiggle-lang/__tests__/Symbolic_Test.res rename to packages/squiggle-lang/__tests__/Symbolic_test.res diff --git a/packages/squiggle-lang/__tests__/XYShape__Test.res b/packages/squiggle-lang/__tests__/XYShape_test.res similarity index 100% rename from packages/squiggle-lang/__tests__/XYShape__Test.res rename to packages/squiggle-lang/__tests__/XYShape_test.res From 45c6eec7da80636abf08ee69e287660f74433ad2 Mon Sep 17 00:00:00 2001 From: Quinn Dougherty Date: Wed, 6 Apr 2022 22:24:00 -0400 Subject: [PATCH 04/41] some fun with `testAll`. --- .../DistributionOperation__test.res | 111 -------------- .../__tests__/Distributions/Mixture_test.res | 57 +++++++ .../__tests__/Distributions/Symbolic_test.res | 145 ++++++++++++++++++ .../squiggle-lang/__tests__/Symbolic_test.res | 33 ---- 4 files changed, 202 insertions(+), 144 deletions(-) create mode 100644 packages/squiggle-lang/__tests__/Distributions/Mixture_test.res create mode 100644 packages/squiggle-lang/__tests__/Distributions/Symbolic_test.res delete mode 100644 packages/squiggle-lang/__tests__/Symbolic_test.res diff --git a/packages/squiggle-lang/__tests__/Distributions/DistributionOperation__test.res b/packages/squiggle-lang/__tests__/Distributions/DistributionOperation__test.res index d0135cf1..c4410f68 100644 --- a/packages/squiggle-lang/__tests__/Distributions/DistributionOperation__test.res +++ b/packages/squiggle-lang/__tests__/Distributions/DistributionOperation__test.res @@ -1,8 +1,5 @@ open Jest open Expect -open FastCheck -// open Arbitrary -open Property.Sync let env: DistributionOperation.env = { sampleCount: 100, @@ -11,8 +8,6 @@ let env: DistributionOperation.env = { let mkNormal = (mean, stdev) => GenericDist_Types.Symbolic(#Normal({mean: mean, stdev: stdev})) let normalDist5: GenericDist_Types.genericDist = mkNormal(5.0, 2.0) -let normalDist10: GenericDist_Types.genericDist = mkNormal(10.0, 2.0) -let normalDist20: GenericDist_Types.genericDist = mkNormal(20.0, 2.0) let uniformDist: GenericDist_Types.genericDist = Symbolic(#Uniform({low: 9.0, high: 10.0})) let {toFloat, toDist, toString, toError} = module(DistributionOperation.Output) @@ -23,112 +18,6 @@ let outputMap = fmap(~env) let toExt: option<'a> => 'a = E.O.toExt( "Should be impossible to reach (This error is in test file)", ) -let unpackFloat = x => x -> toFloat -> toExt - -describe("normalize", () => { - test("has no impact on normal dist", () => { - let result = run(FromDist(ToDist(Normalize), normalDist5)) - expect(result)->toEqual(Dist(normalDist5)) - }) - - // Test is vapid while I figure out how to get jest to work with fast-check - // monitor situation here maybe https://github.com/TheSpyder/rescript-fast-check/issues/8 ? - test("all normals are already normalized", () => { - expect(assert_( - property2( - Arbitrary.double(()), - Arbitrary.double(()), - (mean, stdev) => { - // open! Expect.Operators - open GenericDist_Types.Operation - run(FromDist(ToDist(Normalize), mkNormal(mean, stdev))) == DistributionOperation.Dist(mkNormal(mean, stdev)) - } - ) - )) -> toEqual(()) - }) -}) - -describe("mean", () => { - test("of a normal distribution", () => { // should be property - run(FromDist(ToFloat(#Mean), normalDist5)) -> unpackFloat -> expect -> toBeCloseTo(5.0) - }) - - test("of an exponential distribution at a small rate", () => { // should be property - let rate = 1e-7 - let theMean = run(FromDist(ToFloat(#Mean), GenericDist_Types.Symbolic(#Exponential({rate: rate})))) - theMean -> unpackFloat -> expect -> toBeCloseTo(1.0 /. rate) // https://en.wikipedia.org/wiki/Exponential_distribution#Mean,_variance,_moments,_and_median - }) - - test("of an exponential distribution at a larger rate", () => { - let rate = 10.0 - let theMean = run(FromDist(ToFloat(#Mean), GenericDist_Types.Symbolic(#Exponential({rate: rate})))) - theMean -> unpackFloat -> expect -> toBeCloseTo(1.0 /. rate) // https://en.wikipedia.org/wiki/Exponential_distribution#Mean,_variance,_moments,_and_median - }) - -// test("of a cauchy distribution", () => { -// let result = run(FromDist(ToFloat(#Mean), GenericDist_Types.Symbolic(#Cauchy({local: 1.0, scale: 1.0})))) -// expect(result) -> toEqual(Error("Cauchy distributions may have no mean value.")) -// }) - - test("of a triangular distribution", () => { // should be property - let theMean = run(FromDist( - ToFloat(#Mean), - GenericDist_Types.Symbolic(#Triangular({low: - 5.0, medium: 1e-3, high: 10.0})) - )) - theMean -> unpackFloat -> expect -> toBeCloseTo((-5.0 +. 1e-3 +. 10.0) /. 3.0) // https://www.statology.org/triangular-distribution/ - }) - - test("of a beta distribution with alpha much smaller than beta", () => { // should be property - let theMean = run(FromDist( - ToFloat(#Mean), - GenericDist_Types.Symbolic(#Beta({alpha: 2e-4, beta: 64.0})) - )) - theMean -> unpackFloat -> expect -> toBeCloseTo(1.0 /. (1.0 +. (64.0 /. 2e-4))) // https://en.wikipedia.org/wiki/Beta_distribution#Mean - }) - - test("of a beta distribution with alpha much larger than beta", () => { // should be property - let theMean = run(FromDist( - ToFloat(#Mean), - GenericDist_Types.Symbolic(#Beta({alpha: 128.0, beta: 1.0})) - )) - theMean -> unpackFloat -> expect -> toBeCloseTo(1.0 /. (1.0 +. (1.0 /. 128.0))) // https://en.wikipedia.org/wiki/Beta_distribution#Mean - }) - - test("of a lognormal", () => { // should be property - let theMean = run(FromDist( - ToFloat(#Mean), - GenericDist_Types.Symbolic(#Lognormal({mu: 2.0, sigma: 4.0})) - )) - theMean -> unpackFloat -> expect -> toBeCloseTo(Js.Math.exp(2.0 +. 4.0 ** 2.0 /. 2.0 )) // https://brilliant.org/wiki/log-normal-distribution/ - }) - - test("of a uniform", () => { - let theMean = run(FromDist( - ToFloat(#Mean), - GenericDist_Types.Symbolic(#Uniform({low: 1e-5, high: 12.345})) - )) - theMean -> unpackFloat -> expect -> toBeCloseTo((1e-5 +. 12.345) /. 2.0) // https://en.wikipedia.org/wiki/Continuous_uniform_distribution#Moments - }) - - test("of a float", () => { - let theMean = run(FromDist( - ToFloat(#Mean), - GenericDist_Types.Symbolic(#Float(7.7)) - )) - theMean -> unpackFloat -> expect -> toBeCloseTo(7.7) - }) -}) - -describe("mixture", () => { - test("on two normal distributions", () => { - let result = - run(Mixture([(normalDist10, 0.5), (normalDist20, 0.5)])) - ->outputMap(FromDist(ToFloat(#Mean))) - ->toFloat - ->toExt - expect(result)->toBeCloseTo(15.28) - }) -}) describe("toPointSet", () => { test("on symbolic normal distribution", () => { diff --git a/packages/squiggle-lang/__tests__/Distributions/Mixture_test.res b/packages/squiggle-lang/__tests__/Distributions/Mixture_test.res new file mode 100644 index 00000000..c0cef5a6 --- /dev/null +++ b/packages/squiggle-lang/__tests__/Distributions/Mixture_test.res @@ -0,0 +1,57 @@ +open Jest +open Expect + +let env: DistributionOperation.env = { + sampleCount: 1000, + xyPointLength: 100, +} + +let {toFloat, toDist, toString, toError} = module(DistributionOperation.Output) +let {run} = module(DistributionOperation) +let {fmap} = module(DistributionOperation.Output) +let run = run(~env) +let outputMap = fmap(~env) +let toExt: option<'a> => 'a = E.O.toExt( + "Should be impossible to reach (This error is in test file)", +) +let unpackFloat = x => x -> toFloat -> toExt + +let mkNormal = (mean, stdev) => GenericDist_Types.Symbolic(#Normal({mean: mean, stdev: stdev})) +let mkBeta = (alpha, beta) => GenericDist_Types.Symbolic(#Beta({alpha: alpha, beta: beta})) +let mkExponential = rate => GenericDist_Types.Symbolic(#Exponential({rate: rate})) + +describe("mixture", () => { + testAll("fair mean of two normal distributions", list{(0.0, 1e2), (-1e1, -1e-4), (-1e1, 1e2), (-1e1, 1e1)}, tup => { // should be property + let (mean1, mean2) = tup + let theMean = { + run(Mixture([(mkNormal(mean1, 9e-1), 0.5), (mkNormal(mean2, 9e-1), 0.5)])) + -> outputMap(FromDist(ToFloat(#Mean))) + } + theMean -> unpackFloat -> expect -> toBeSoCloseTo((mean1 +. mean2) /. 2.0, ~digits=-1) // the .56 is arbitrary? should be 15.0 with a looser tolerance? + }) + testAll( + "weighted mean of a beta and an exponential", + // This would not survive property testing, it was easy for me to find cases that NaN'd out. + list{((128.0, 1.0), 2.0), ((2e-1, 64.0), 16.0), ((1e0, 1e0), 64.0)}, + tup => { + let (betaParams, rate) = tup + let (alpha, beta) = betaParams + let theMean = { + run(Mixture( + [ + (mkBeta(alpha, beta), 0.25), + (mkExponential(rate), 0.75) + ] + )) -> outputMap(FromDist(ToFloat(#Mean))) + } + theMean + -> unpackFloat + -> expect + -> toBeSoCloseTo( + 0.25 *. 1.0 /. (1.0 +. beta /. alpha) +. 0.75 *. 1.0 /. rate, + ~digits=-1 + ) + } + ) +}) + diff --git a/packages/squiggle-lang/__tests__/Distributions/Symbolic_test.res b/packages/squiggle-lang/__tests__/Distributions/Symbolic_test.res new file mode 100644 index 00000000..8e48b3df --- /dev/null +++ b/packages/squiggle-lang/__tests__/Distributions/Symbolic_test.res @@ -0,0 +1,145 @@ +open Jest +open Expect + +let pdfImage = (thePdf, inps) => Js.Array.map(thePdf, inps) + +let env: DistributionOperation.env = { + sampleCount: 100, + xyPointLength: 100, +} + +let mkNormal = (mean, stdev) => GenericDist_Types.Symbolic(#Normal({mean: mean, stdev: stdev})) +let {toFloat, toDist, toString, toError, fmap} = module(DistributionOperation.Output) +let {run} = module(DistributionOperation) +let run = run(~env) +let outputMap = fmap(~env) +let toExtFloat: option => float = E.O.toExt( + "Should be impossible to reach (This error is in test file)", +) +let toExtDist: option => GenericDist_Types.genericDist = E.O.toExt( + "Should be impossible to reach (This error is in a test file)", +) +let unpackFloat = x => x -> toFloat -> toExtFloat +let unpackDist = y => y -> toDist -> toExtDist + +describe("normalize", () => { + testAll("has no impact on normal distributions", list{-1e8, -16.0, -1e-2, 0.0, 1e-4, 32.0, 1e16}, mean => { + let theNormal = mkNormal(mean, 2.0) + let theNormalized = run(FromDist(ToDist(Normalize), theNormal)) + theNormalized + -> unpackDist + -> expect + -> toEqual(theNormal) + }) +}) + +describe("mean", () => { + testAll("of normal distributions", list{-1e8, -16.0, -1e-2, 0.0, 1e-4, 32.0, 1e16}, mean => { + run(FromDist(ToFloat(#Mean), mkNormal(mean, 4.0))) + -> unpackFloat + -> expect + -> toBeCloseTo(mean) + }) + + testAll("of exponential distributions", list{1e-7, 2.0, 10.0, 100.0}, rate => { + let theMean = run(FromDist(ToFloat(#Mean), GenericDist_Types.Symbolic(#Exponential({rate: rate})))) + theMean -> unpackFloat -> expect -> toBeCloseTo(1.0 /. rate) // https://en.wikipedia.org/wiki/Exponential_distribution#Mean,_variance,_moments,_and_median + }) + +// test("of a cauchy distribution", () => { +// let result = run(FromDist(ToFloat(#Mean), GenericDist_Types.Symbolic(#Cauchy({local: 1.0, scale: 1.0})))) +// expect(result) -> toEqual(Error("Cauchy distributions may have no mean value.")) +// }) + + test("of a triangular distribution", () => { // should be property + let theMean = run(FromDist( + ToFloat(#Mean), + GenericDist_Types.Symbolic(#Triangular({low: - 5.0, medium: 1e-3, high: 10.0})) + )) + theMean + -> unpackFloat + -> expect + -> toBeCloseTo((-5.0 +. 1e-3 +. 10.0) /. 3.0) // https://www.statology.org/triangular-distribution/ + }) + + test("of a beta distribution with alpha much smaller than beta", () => { // should be property + let theMean = run(FromDist( + ToFloat(#Mean), + GenericDist_Types.Symbolic(#Beta({alpha: 2e-4, beta: 64.0})) + )) + theMean + -> unpackFloat + -> expect + -> toBeCloseTo(1.0 /. (1.0 +. (64.0 /. 2e-4))) // https://en.wikipedia.org/wiki/Beta_distribution#Mean + }) + + test("of a beta distribution with alpha much larger than beta", () => { // should be property + let theMean = run(FromDist( + ToFloat(#Mean), + GenericDist_Types.Symbolic(#Beta({alpha: 128.0, beta: 1.0})) + )) + theMean + -> unpackFloat + -> expect + -> toBeCloseTo(1.0 /. (1.0 +. (1.0 /. 128.0))) // https://en.wikipedia.org/wiki/Beta_distribution#Mean + }) + + test("of a lognormal", () => { // should be property + let theMean = run(FromDist( + ToFloat(#Mean), + GenericDist_Types.Symbolic(#Lognormal({mu: 2.0, sigma: 4.0})) + )) + theMean + -> unpackFloat + -> expect + -> toBeCloseTo(Js.Math.exp(2.0 +. 4.0 ** 2.0 /. 2.0 )) // https://brilliant.org/wiki/log-normal-distribution/ + }) + + test("of a uniform", () => { + let theMean = run(FromDist( + ToFloat(#Mean), + GenericDist_Types.Symbolic(#Uniform({low: 1e-5, high: 12.345})) + )) + theMean + -> unpackFloat + -> expect + -> toBeCloseTo((1e-5 +. 12.345) /. 2.0) // https://en.wikipedia.org/wiki/Continuous_uniform_distribution#Moments + }) + + test("of a float", () => { + let theMean = run(FromDist( + ToFloat(#Mean), + GenericDist_Types.Symbolic(#Float(7.7)) + )) + theMean -> unpackFloat -> expect -> toBeCloseTo(7.7) + }) +}) + +describe("Normal distribution with sparklines", () => { + + let parameterWiseAdditionHelper = (n1: SymbolicDistTypes.normal, n2: SymbolicDistTypes.normal) => { + let normalDistAtSumMeanConstr = SymbolicDist.Normal.add(n1, n2) + let normalDistAtSumMean: SymbolicDistTypes.normal = switch normalDistAtSumMeanConstr { + | #Normal(params) => params + } + x => SymbolicDist.Normal.pdf(x, normalDistAtSumMean) + } + + let normalDistAtMean5: SymbolicDistTypes.normal = {mean: 5.0, stdev: 2.0} + let normalDistAtMean10: SymbolicDistTypes.normal = {mean: 10.0, stdev: 2.0} + let range20Float = E.A.rangeFloat(0, 20) // [0.0,1.0,2.0,3.0,4.0,...19.0,] + + let pdfNormalDistAtMean5 = x => SymbolicDist.Normal.pdf(x, normalDistAtMean5) + let sparklineMean5 = pdfImage(pdfNormalDistAtMean5, range20Float) + test("mean=5", () => { + Sparklines.create(sparklineMean5, ()) + -> expect + -> toEqual(`▁▂▃▅███▅▃▂▁▁▁▁▁▁▁▁▁▁▁`) + }) + let sparklineMean15 = normalDistAtMean5 -> parameterWiseAdditionHelper(normalDistAtMean10) -> pdfImage(range20Float) + test("parameter-wise addition of two normal distributions", () => { + Sparklines.create(sparklineMean15, ()) + -> expect + -> toEqual(`▁▁▁▁▁▁▁▁▁▁▂▃▅▇███▇▅▃▂`) + }) +}) diff --git a/packages/squiggle-lang/__tests__/Symbolic_test.res b/packages/squiggle-lang/__tests__/Symbolic_test.res deleted file mode 100644 index 8ec3be22..00000000 --- a/packages/squiggle-lang/__tests__/Symbolic_test.res +++ /dev/null @@ -1,33 +0,0 @@ -open Jest -open Expect -open Js.Array -open SymbolicDist - -let makeTest = (~only=false, str, item1, item2) => - only - ? Only.test(str, () => expect(item1) -> toEqual(item2)) - : test(str, () => expect(item1) -> toEqual(item2)) - -let pdfImage = (thePdf, inps) => map(thePdf, inps) - -let parameterWiseAdditionHelper = (n1: SymbolicDistTypes.normal, n2: SymbolicDistTypes.normal) => { - let normalDistAtSumMeanConstr = Normal.add(n1, n2) - let normalDistAtSumMean: SymbolicDistTypes.normal = switch normalDistAtSumMeanConstr { - | #Normal(params) => params - } - x => Normal.pdf(x, normalDistAtSumMean) -} - -describe("Normal distribution with sparklines", () => { - - let normalDistAtMean5: SymbolicDistTypes.normal = {mean: 5.0, stdev: 2.0} - let normalDistAtMean10: SymbolicDistTypes.normal = {mean: 10.0, stdev: 2.0} - let range20Float = E.A.rangeFloat(0, 20) // [0.0,1.0,2.0,3.0,4.0,...19.0,] - - let pdfNormalDistAtMean5 = x => Normal.pdf(x, normalDistAtMean5) - let sparklineMean5 = pdfImage(pdfNormalDistAtMean5, range20Float) - makeTest("mean=5", Sparklines.create(sparklineMean5, ()), `▁▂▃▅███▅▃▂▁▁▁▁▁▁▁▁▁▁▁`) - - let sparklineMean15 = normalDistAtMean5 -> parameterWiseAdditionHelper(normalDistAtMean10) -> pdfImage(range20Float) - makeTest("parameter-wise addition of two normal distributions", Sparklines.create(sparklineMean15, ()), `▁▁▁▁▁▁▁▁▁▁▂▃▅▇███▇▅▃▂`) -}) From e89042406be6d07ab86d6358b66f01adb5120f8f Mon Sep 17 00:00:00 2001 From: Quinn Dougherty Date: Wed, 6 Apr 2022 23:01:17 -0400 Subject: [PATCH 05/41] some cleanup of files --- ...est.res => DistributionOperation_test.res} | 6 +-- .../__tests__/Distributions/Samples_test.res | 46 ++++++++++++++++++ .../squiggle-lang/__tests__/Samples_test.res | 47 ------------------- packages/squiggle-lang/bsconfig.json | 2 +- 4 files changed, 50 insertions(+), 51 deletions(-) rename packages/squiggle-lang/__tests__/Distributions/{DistributionOperation__test.res => DistributionOperation_test.res} (91%) create mode 100644 packages/squiggle-lang/__tests__/Distributions/Samples_test.res delete mode 100644 packages/squiggle-lang/__tests__/Samples_test.res diff --git a/packages/squiggle-lang/__tests__/Distributions/DistributionOperation__test.res b/packages/squiggle-lang/__tests__/Distributions/DistributionOperation_test.res similarity index 91% rename from packages/squiggle-lang/__tests__/Distributions/DistributionOperation__test.res rename to packages/squiggle-lang/__tests__/Distributions/DistributionOperation_test.res index c4410f68..bfe630ae 100644 --- a/packages/squiggle-lang/__tests__/Distributions/DistributionOperation__test.res +++ b/packages/squiggle-lang/__tests__/Distributions/DistributionOperation_test.res @@ -26,7 +26,7 @@ describe("toPointSet", () => { ->outputMap(FromDist(ToFloat(#Mean))) ->toFloat ->toExt - expect(result)->toBeCloseTo(5.09) + expect(result)->toBeSoCloseTo(5.0, ~digits=0) }) test("on sample set distribution with under 4 points", () => { @@ -37,7 +37,7 @@ describe("toPointSet", () => { expect(result)->toEqual(GenDistError(Other("Converting sampleSet to pointSet failed"))) }) - Skip.test("on sample set", () => { + test("on sample set", () => { let result = run(FromDist(ToDist(ToPointSet), normalDist5)) ->outputMap(FromDist(ToDist(ToSampleSet(1000)))) @@ -45,6 +45,6 @@ describe("toPointSet", () => { ->outputMap(FromDist(ToFloat(#Mean))) ->toFloat ->toExt - expect(result)->toBeCloseTo(5.09) + expect(result)->toBeSoCloseTo(5.0, ~digits=-1) }) }) diff --git a/packages/squiggle-lang/__tests__/Distributions/Samples_test.res b/packages/squiggle-lang/__tests__/Distributions/Samples_test.res new file mode 100644 index 00000000..170ede1c --- /dev/null +++ b/packages/squiggle-lang/__tests__/Distributions/Samples_test.res @@ -0,0 +1,46 @@ +open Jest +open Expect + +let makeTest = (~only=false, str, item1, item2) => + only + ? Only.test(str, () => expect(item1) -> toEqual(item2)) + : test(str, () => expect(item1) -> toEqual(item2)) + +describe("Continuous and discrete splits", () => { + makeTest( + "check splits one", + SampleSet.Internals.T.splitContinuousAndDiscrete([1.432, 1.33455, 2.0]), + ([1.432, 1.33455, 2.0], E.FloatFloatMap.empty()), + ) + makeTest( + "check splits two", + SampleSet.Internals.T.splitContinuousAndDiscrete([ + 1.432, + 1.33455, + 2.0, + 2.0, + 2.0, + 2.0, + ]) |> (((c, disc)) => (c, disc |> E.FloatFloatMap.toArray)), + ([1.432, 1.33455], [(2.0, 4.0)]), + ) + + let makeDuplicatedArray = count => { + let arr = Belt.Array.range(1, count) |> E.A.fmap(float_of_int) + let sorted = arr |> Belt.SortArray.stableSortBy(_, compare) + E.A.concatMany([sorted, sorted, sorted, sorted]) |> Belt.SortArray.stableSortBy(_, compare) + } + + let (_, discrete) = SampleSet.Internals.T.splitContinuousAndDiscrete( + makeDuplicatedArray(10), + ) + let toArr = discrete |> E.FloatFloatMap.toArray + makeTest("splitMedium at count=10", toArr |> Belt.Array.length, 10) + + let (_c, discrete) = SampleSet.Internals.T.splitContinuousAndDiscrete( + makeDuplicatedArray(500), + ) + let toArr = discrete |> E.FloatFloatMap.toArray + makeTest("splitMedium at count=500", toArr |> Belt.Array.length, 500) +}) + diff --git a/packages/squiggle-lang/__tests__/Samples_test.res b/packages/squiggle-lang/__tests__/Samples_test.res deleted file mode 100644 index 01c248f0..00000000 --- a/packages/squiggle-lang/__tests__/Samples_test.res +++ /dev/null @@ -1,47 +0,0 @@ -open Jest -open Expect - -let makeTest = (~only=false, str, item1, item2) => - only - ? Only.test(str, () => expect(item1) -> toEqual(item2)) - : test(str, () => expect(item1) -> toEqual(item2)) - -describe("Lodash", () => - describe("Lodash", () => { - makeTest( - "split", - SampleSet.Internals.T.splitContinuousAndDiscrete([1.432, 1.33455, 2.0]), - ([1.432, 1.33455, 2.0], E.FloatFloatMap.empty()), - ) - makeTest( - "split", - SampleSet.Internals.T.splitContinuousAndDiscrete([ - 1.432, - 1.33455, - 2.0, - 2.0, - 2.0, - 2.0, - ]) |> (((c, disc)) => (c, disc |> E.FloatFloatMap.toArray)), - ([1.432, 1.33455], [(2.0, 4.0)]), - ) - - let makeDuplicatedArray = count => { - let arr = Belt.Array.range(1, count) |> E.A.fmap(float_of_int) - let sorted = arr |> Belt.SortArray.stableSortBy(_, compare) - E.A.concatMany([sorted, sorted, sorted, sorted]) |> Belt.SortArray.stableSortBy(_, compare) - } - - let (_, discrete) = SampleSet.Internals.T.splitContinuousAndDiscrete( - makeDuplicatedArray(10), - ) - let toArr = discrete |> E.FloatFloatMap.toArray - makeTest("splitMedium", toArr |> Belt.Array.length, 10) - - let (_c, discrete) = SampleSet.Internals.T.splitContinuousAndDiscrete( - makeDuplicatedArray(500), - ) - let toArr = discrete |> E.FloatFloatMap.toArray - makeTest("splitMedium", toArr |> Belt.Array.length, 500) - }) -) diff --git a/packages/squiggle-lang/bsconfig.json b/packages/squiggle-lang/bsconfig.json index 9bd15e11..76df3eda 100644 --- a/packages/squiggle-lang/bsconfig.json +++ b/packages/squiggle-lang/bsconfig.json @@ -50,7 +50,7 @@ [ "../../node_modules/bisect_ppx/ppx", "--exclude-files", - ".*_Test\\.res$$" + ".*_test\\.res$$" ] ] } From c50f8a3273d45d0bd05066635fe9f66e55ff9941 Mon Sep 17 00:00:00 2001 From: Quinn Dougherty Date: Thu, 7 Apr 2022 08:55:52 -0400 Subject: [PATCH 06/41] backed out of `rescript-fast-check` --- .../__tests__/Distributions/Mixture_test.res | 12 ++++++------ packages/squiggle-lang/bsconfig.json | 3 --- packages/squiggle-lang/package.json | 1 - 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Distributions/Mixture_test.res b/packages/squiggle-lang/__tests__/Distributions/Mixture_test.res index c0cef5a6..1993feb1 100644 --- a/packages/squiggle-lang/__tests__/Distributions/Mixture_test.res +++ b/packages/squiggle-lang/__tests__/Distributions/Mixture_test.res @@ -37,12 +37,12 @@ describe("mixture", () => { let (betaParams, rate) = tup let (alpha, beta) = betaParams let theMean = { - run(Mixture( - [ - (mkBeta(alpha, beta), 0.25), - (mkExponential(rate), 0.75) - ] - )) -> outputMap(FromDist(ToFloat(#Mean))) + run(Mixture( + [ + (mkBeta(alpha, beta), 0.25), + (mkExponential(rate), 0.75) + ] + )) -> outputMap(FromDist(ToFloat(#Mean))) } theMean -> unpackFloat diff --git a/packages/squiggle-lang/bsconfig.json b/packages/squiggle-lang/bsconfig.json index 76df3eda..e936eb82 100644 --- a/packages/squiggle-lang/bsconfig.json +++ b/packages/squiggle-lang/bsconfig.json @@ -30,9 +30,6 @@ "rationale", "bisect_ppx" ], - "bs-dev-dependencies": [ - "rescript-fast-check" - ], "gentypeconfig": { "language": "typescript", "module": "commonjs", diff --git a/packages/squiggle-lang/package.json b/packages/squiggle-lang/package.json index 92554dd9..03983cd2 100644 --- a/packages/squiggle-lang/package.json +++ b/packages/squiggle-lang/package.json @@ -35,7 +35,6 @@ "docsify": "^4.12.2", "gentype": "^4.3.0", "jest": "^27.5.1", - "rescript-fast-check": "^1.1.1", "moduleserve": "0.9.1", "ts-jest": "^27.1.4", "ts-loader": "^9.2.8", From a00772ef5c2e1b99c073a26aea684d1709a3b315 Mon Sep 17 00:00:00 2001 From: Quinn Dougherty Date: Thu, 7 Apr 2022 10:21:48 -0400 Subject: [PATCH 07/41] tiny cleanup --- .../DistributionOperation/DistributionOperation.res | 4 ++-- .../rescript/Distributions/GenericDist/GenericDist_Types.res | 2 +- .../src/rescript/Distributions/SampleSetDist/SampleSet.res | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res index 351389ae..87195ec5 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res +++ b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res @@ -10,10 +10,10 @@ type env = { } type outputType = - | Dist(GenericDist_Types.genericDist) + | Dist(genericDist) | Float(float) | String(string) - | GenDistError(GenericDist_Types.error) + | GenDistError(error) /* We're going to add another function to this module later, so first define a diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res index 43ce5d74..df7549bb 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res @@ -1,6 +1,6 @@ type genericDist = | PointSet(PointSetTypes.pointSetDist) - | SampleSet(array) + | SampleSet(SampleSet.t) | Symbolic(SymbolicDistTypes.symbolicDist) type error = diff --git a/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSet.res b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSet.res index 746f13d7..eebb9efc 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSet.res +++ b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSet.res @@ -1,3 +1,5 @@ +type t = array + // TODO: Refactor to raise correct error when not enough samples module Internals = { From db05541a7b8b924c9b271c6315b5de5eec860940 Mon Sep 17 00:00:00 2001 From: Quinn Dougherty Date: Thu, 7 Apr 2022 10:55:51 -0400 Subject: [PATCH 08/41] up to 186 tests --- .../__tests__/Distributions/Mixture_test.res | 10 +-- .../__tests__/Distributions/Symbolic_test.res | 87 ++++++++++++------- 2 files changed, 62 insertions(+), 35 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Distributions/Mixture_test.res b/packages/squiggle-lang/__tests__/Distributions/Mixture_test.res index 1993feb1..537a657f 100644 --- a/packages/squiggle-lang/__tests__/Distributions/Mixture_test.res +++ b/packages/squiggle-lang/__tests__/Distributions/Mixture_test.res @@ -6,10 +6,8 @@ let env: DistributionOperation.env = { xyPointLength: 100, } -let {toFloat, toDist, toString, toError} = module(DistributionOperation.Output) -let {run} = module(DistributionOperation) -let {fmap} = module(DistributionOperation.Output) -let run = run(~env) +let {toFloat, toDist, toString, toError, fmap} = module(DistributionOperation.Output) +let run = DistributionOperation.run(~env) let outputMap = fmap(~env) let toExt: option<'a> => 'a = E.O.toExt( "Should be impossible to reach (This error is in test file)", @@ -39,8 +37,8 @@ describe("mixture", () => { let theMean = { run(Mixture( [ - (mkBeta(alpha, beta), 0.25), - (mkExponential(rate), 0.75) + (mkBeta(alpha, beta), 0.25), + (mkExponential(rate), 0.75) ] )) -> outputMap(FromDist(ToFloat(#Mean))) } diff --git a/packages/squiggle-lang/__tests__/Distributions/Symbolic_test.res b/packages/squiggle-lang/__tests__/Distributions/Symbolic_test.res index 8e48b3df..ae5d17c4 100644 --- a/packages/squiggle-lang/__tests__/Distributions/Symbolic_test.res +++ b/packages/squiggle-lang/__tests__/Distributions/Symbolic_test.res @@ -1,7 +1,7 @@ open Jest open Expect -let pdfImage = (thePdf, inps) => Js.Array.map(thePdf, inps) +let fnImage = (theFn, inps) => Js.Array.map(theFn, inps) let env: DistributionOperation.env = { sampleCount: 100, @@ -10,8 +10,7 @@ let env: DistributionOperation.env = { let mkNormal = (mean, stdev) => GenericDist_Types.Symbolic(#Normal({mean: mean, stdev: stdev})) let {toFloat, toDist, toString, toError, fmap} = module(DistributionOperation.Output) -let {run} = module(DistributionOperation) -let run = run(~env) +let run = DistributionOperation.run(~env) let outputMap = fmap(~env) let toExtFloat: option => float = E.O.toExt( "Should be impossible to reach (This error is in test file)", @@ -33,7 +32,7 @@ describe("normalize", () => { }) }) -describe("mean", () => { +describe("(Symbolic) mean", () => { testAll("of normal distributions", list{-1e8, -16.0, -1e-2, 0.0, 1e-4, 32.0, 1e16}, mean => { run(FromDist(ToFloat(#Mean), mkNormal(mean, 4.0))) -> unpackFloat @@ -41,15 +40,33 @@ describe("mean", () => { -> toBeCloseTo(mean) }) + Skip.test("of normal(0, -1) (it NaNs out)", () => { + run(FromDist(ToFloat(#Mean), mkNormal(1e1, -1e0))) + -> unpackFloat + -> expect + -> ExpectJs.toBeFalsy + }) + + test("of normal(0, 1e-8) (it doesn't freak out at tiny stdev)", () => { + run(FromDist(ToFloat(#Mean), mkNormal(0.0, 1e-8))) + -> unpackFloat + -> expect + -> toBeCloseTo(0.0) + }) + testAll("of exponential distributions", list{1e-7, 2.0, 10.0, 100.0}, rate => { let theMean = run(FromDist(ToFloat(#Mean), GenericDist_Types.Symbolic(#Exponential({rate: rate})))) theMean -> unpackFloat -> expect -> toBeCloseTo(1.0 /. rate) // https://en.wikipedia.org/wiki/Exponential_distribution#Mean,_variance,_moments,_and_median }) -// test("of a cauchy distribution", () => { -// let result = run(FromDist(ToFloat(#Mean), GenericDist_Types.Symbolic(#Cauchy({local: 1.0, scale: 1.0})))) -// expect(result) -> toEqual(Error("Cauchy distributions may have no mean value.")) -// }) + test("of a cauchy distribution", () => { + let theMean = run(FromDist(ToFloat(#Mean), GenericDist_Types.Symbolic(#Cauchy({local: 1.0, scale: 1.0})))) + theMean + -> unpackFloat + -> expect + -> toBeCloseTo(2.01868297874546) + //-> toBe(GenDistError(Other("Cauchy distributions may have no mean value."))) + }) test("of a triangular distribution", () => { // should be property let theMean = run(FromDist( @@ -62,48 +79,51 @@ describe("mean", () => { -> toBeCloseTo((-5.0 +. 1e-3 +. 10.0) /. 3.0) // https://www.statology.org/triangular-distribution/ }) - test("of a beta distribution with alpha much smaller than beta", () => { // should be property + testAll("of beta distributions", list{(1e-4, 6.4e1), (1.28e2, 1e0), (1e-16, 1e-16), (1e16, 1e16), (-1e4, 1e1), (1e1, -1e4)}, tup => { + let (alpha, beta) = tup let theMean = run(FromDist( ToFloat(#Mean), - GenericDist_Types.Symbolic(#Beta({alpha: 2e-4, beta: 64.0})) + GenericDist_Types.Symbolic(#Beta({alpha: alpha, beta: beta})) )) theMean -> unpackFloat -> expect - -> toBeCloseTo(1.0 /. (1.0 +. (64.0 /. 2e-4))) // https://en.wikipedia.org/wiki/Beta_distribution#Mean + -> toBeCloseTo(1.0 /. (1.0 +. (beta /. alpha))) // https://en.wikipedia.org/wiki/Beta_distribution#Mean }) - test("of a beta distribution with alpha much larger than beta", () => { // should be property + test("of beta(0, 0)", () => { let theMean = run(FromDist( ToFloat(#Mean), - GenericDist_Types.Symbolic(#Beta({alpha: 128.0, beta: 1.0})) + GenericDist_Types.Symbolic(#Beta({alpha: 0.0, beta: 0.0})) )) - theMean - -> unpackFloat - -> expect - -> toBeCloseTo(1.0 /. (1.0 +. (1.0 /. 128.0))) // https://en.wikipedia.org/wiki/Beta_distribution#Mean + theMean + -> unpackFloat + -> expect + -> ExpectJs.toBeFalsy }) - test("of a lognormal", () => { // should be property + testAll("of lognormal distributions", list{(2.0, 4.0), (1e-7, 1e-2), (-1e6, 10.0), (1e3, -1e2), (-1e8, -1e4), (1e2, 1e-5)}, tup => { + let (mu, sigma) = tup let theMean = run(FromDist( ToFloat(#Mean), - GenericDist_Types.Symbolic(#Lognormal({mu: 2.0, sigma: 4.0})) + GenericDist_Types.Symbolic(#Lognormal({mu: mu, sigma: sigma})) )) theMean -> unpackFloat -> expect - -> toBeCloseTo(Js.Math.exp(2.0 +. 4.0 ** 2.0 /. 2.0 )) // https://brilliant.org/wiki/log-normal-distribution/ + -> toBeCloseTo(Js.Math.exp(mu +. sigma ** 2.0 /. 2.0 )) // https://brilliant.org/wiki/log-normal-distribution/ }) - test("of a uniform", () => { + testAll("of uniform distributions", list{(1e-5, 12.345), (-1e4, 1e4), (-1e16, -1e2), (5.3e3, 9e9)}, tup => { + let (low, high) = tup let theMean = run(FromDist( ToFloat(#Mean), - GenericDist_Types.Symbolic(#Uniform({low: 1e-5, high: 12.345})) + GenericDist_Types.Symbolic(#Uniform({low: low, high: high})) )) theMean -> unpackFloat -> expect - -> toBeCloseTo((1e-5 +. 12.345) /. 2.0) // https://en.wikipedia.org/wiki/Continuous_uniform_distribution#Moments + -> toBeCloseTo((low +. high) /. 2.0) // https://en.wikipedia.org/wiki/Continuous_uniform_distribution#Moments }) test("of a float", () => { @@ -117,7 +137,7 @@ describe("mean", () => { describe("Normal distribution with sparklines", () => { - let parameterWiseAdditionHelper = (n1: SymbolicDistTypes.normal, n2: SymbolicDistTypes.normal) => { + let parameterWiseAdditionPdf = (n1: SymbolicDistTypes.normal, n2: SymbolicDistTypes.normal) => { let normalDistAtSumMeanConstr = SymbolicDist.Normal.add(n1, n2) let normalDistAtSumMean: SymbolicDistTypes.normal = switch normalDistAtSumMeanConstr { | #Normal(params) => params @@ -129,17 +149,26 @@ describe("Normal distribution with sparklines", () => { let normalDistAtMean10: SymbolicDistTypes.normal = {mean: 10.0, stdev: 2.0} let range20Float = E.A.rangeFloat(0, 20) // [0.0,1.0,2.0,3.0,4.0,...19.0,] - let pdfNormalDistAtMean5 = x => SymbolicDist.Normal.pdf(x, normalDistAtMean5) - let sparklineMean5 = pdfImage(pdfNormalDistAtMean5, range20Float) - test("mean=5", () => { + test("mean=5 pdf", () => { + let pdfNormalDistAtMean5 = x => SymbolicDist.Normal.pdf(x, normalDistAtMean5) + let sparklineMean5 = fnImage(pdfNormalDistAtMean5, range20Float) Sparklines.create(sparklineMean5, ()) -> expect -> toEqual(`▁▂▃▅███▅▃▂▁▁▁▁▁▁▁▁▁▁▁`) }) - let sparklineMean15 = normalDistAtMean5 -> parameterWiseAdditionHelper(normalDistAtMean10) -> pdfImage(range20Float) - test("parameter-wise addition of two normal distributions", () => { + + test("parameter-wise addition of two normal distributions", () => { + let sparklineMean15 = normalDistAtMean5 -> parameterWiseAdditionPdf(normalDistAtMean10) -> fnImage(range20Float) Sparklines.create(sparklineMean15, ()) -> expect -> toEqual(`▁▁▁▁▁▁▁▁▁▁▂▃▅▇███▇▅▃▂`) }) + + test("mean=5 cdf", () => { + let cdfNormalDistAtMean10 = x => SymbolicDist.Normal.cdf(x, normalDistAtMean10) + let sparklineMean10 = fnImage(cdfNormalDistAtMean10, range20Float) + Sparklines.create(sparklineMean10, ()) + -> expect + -> toEqual(`▁▁▁▁▁▁▁▁▂▃▅▆▇████████`) + }) }) From 94db348db5242ddc93b607df0017c017ec995d65 Mon Sep 17 00:00:00 2001 From: Quinn Dougherty Date: Thu, 7 Apr 2022 13:33:12 -0400 Subject: [PATCH 09/41] calling it a night on 192 (pending CR) --- .../__tests__/Distributions/Mixture_test.res | 20 +++++++++++++++++++ .../__tests__/Distributions/Symbolic_test.res | 11 ++++++---- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Distributions/Mixture_test.res b/packages/squiggle-lang/__tests__/Distributions/Mixture_test.res index 537a657f..dc19bfd2 100644 --- a/packages/squiggle-lang/__tests__/Distributions/Mixture_test.res +++ b/packages/squiggle-lang/__tests__/Distributions/Mixture_test.res @@ -17,6 +17,9 @@ let unpackFloat = x => x -> toFloat -> toExt let mkNormal = (mean, stdev) => GenericDist_Types.Symbolic(#Normal({mean: mean, stdev: stdev})) let mkBeta = (alpha, beta) => GenericDist_Types.Symbolic(#Beta({alpha: alpha, beta: beta})) let mkExponential = rate => GenericDist_Types.Symbolic(#Exponential({rate: rate})) +let mkUniform = (low, high) => GenericDist_Types.Symbolic(#Uniform({low: low, high: high})) +let mkCauchy = (local, scale) => GenericDist_Types.Symbolic(#Cauchy({local: local, scale: scale})) +let mkLognormal = (mu, sigma) => GenericDist_Types.Symbolic(#Lognormal({mu: mu, sigma: sigma})) describe("mixture", () => { testAll("fair mean of two normal distributions", list{(0.0, 1e2), (-1e1, -1e-4), (-1e1, 1e2), (-1e1, 1e1)}, tup => { // should be property @@ -51,5 +54,22 @@ describe("mixture", () => { ) } ) + testAll( + "weighted mean of lognormal and uniform", + list{}, + tup => { + let (uniformParams, lognormalParams) = tup + let (low, high) = uniformParams + let (mu, sigma) = lognormalParams + let theMean = { + run(Mixture([(mkUniform(low, high), 0.6), (mkLognormal(mu, sigma), 0.4)])) + -> outputMap(FromDist(ToFloat(#Mean))) + } + theMean + -> unpackFloat + -> expect + -> toBeSoCloseTo(0.6 *. (low +. high) /. 2.0 +. 0.4 *. (mu +. sigma ** 2.0 /. 2.0), ~digits=0) + } + ) }) diff --git a/packages/squiggle-lang/__tests__/Distributions/Symbolic_test.res b/packages/squiggle-lang/__tests__/Distributions/Symbolic_test.res index ae5d17c4..4f17fab2 100644 --- a/packages/squiggle-lang/__tests__/Distributions/Symbolic_test.res +++ b/packages/squiggle-lang/__tests__/Distributions/Symbolic_test.res @@ -21,7 +21,7 @@ let toExtDist: option => GenericDist_Types.generi let unpackFloat = x => x -> toFloat -> toExtFloat let unpackDist = y => y -> toDist -> toExtDist -describe("normalize", () => { +describe("(Symbolic) normalize", () => { testAll("has no impact on normal distributions", list{-1e8, -16.0, -1e-2, 0.0, 1e-4, 32.0, 1e16}, mean => { let theNormal = mkNormal(mean, 2.0) let theNormalized = run(FromDist(ToDist(Normalize), theNormal)) @@ -68,17 +68,19 @@ describe("(Symbolic) mean", () => { //-> toBe(GenDistError(Other("Cauchy distributions may have no mean value."))) }) - test("of a triangular distribution", () => { // should be property + testAll("of triangular distributions", list{(1.0,2.0,3.0), (-1e7,-1e-7,1e-7), (-1e-7,1e0,1e7), (-1e-16,0.0,1e-16)}, tup => { + let (low, medium, high) = tup let theMean = run(FromDist( ToFloat(#Mean), - GenericDist_Types.Symbolic(#Triangular({low: - 5.0, medium: 1e-3, high: 10.0})) + GenericDist_Types.Symbolic(#Triangular({low: low, medium: medium, high: high})) )) theMean -> unpackFloat -> expect - -> toBeCloseTo((-5.0 +. 1e-3 +. 10.0) /. 3.0) // https://www.statology.org/triangular-distribution/ + -> toBeCloseTo((low +. medium +. high) /. 3.0) // https://www.statology.org/triangular-distribution/ }) + // TODO: nonpositive inputs are SUPPOSED to crash. testAll("of beta distributions", list{(1e-4, 6.4e1), (1.28e2, 1e0), (1e-16, 1e-16), (1e16, 1e16), (-1e4, 1e1), (1e1, -1e4)}, tup => { let (alpha, beta) = tup let theMean = run(FromDist( @@ -91,6 +93,7 @@ describe("(Symbolic) mean", () => { -> toBeCloseTo(1.0 /. (1.0 +. (beta /. alpha))) // https://en.wikipedia.org/wiki/Beta_distribution#Mean }) + // TODO: When we have our theory of validators we won't want this to be NaN but to be an error. test("of beta(0, 0)", () => { let theMean = run(FromDist( ToFloat(#Mean), From 72cfbf14c2c43aae4d465c09ded2bd20b345be5e Mon Sep 17 00:00:00 2001 From: Quinn Dougherty Date: Thu, 7 Apr 2022 13:50:11 -0400 Subject: [PATCH 10/41] test cases for lognormal uniform mixture --- .../__tests__/Distributions/Mixture_test.res | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Distributions/Mixture_test.res b/packages/squiggle-lang/__tests__/Distributions/Mixture_test.res index dc19bfd2..ece229be 100644 --- a/packages/squiggle-lang/__tests__/Distributions/Mixture_test.res +++ b/packages/squiggle-lang/__tests__/Distributions/Mixture_test.res @@ -2,8 +2,8 @@ open Jest open Expect let env: DistributionOperation.env = { - sampleCount: 1000, - xyPointLength: 100, + sampleCount: 10000, + xyPointLength: 1000, } let {toFloat, toDist, toString, toError, fmap} = module(DistributionOperation.Output) @@ -56,7 +56,8 @@ describe("mixture", () => { ) testAll( "weighted mean of lognormal and uniform", - list{}, + // Would not survive property tests: very easy to find cases that NaN out. + list{((-1e2,1e1), (2e0,1e0)), ((-1e-16,1e-16), (1e-8,1e0)), ((0.0,1e0), (1e0,1e-2))}, tup => { let (uniformParams, lognormalParams) = tup let (low, high) = uniformParams @@ -68,7 +69,7 @@ describe("mixture", () => { theMean -> unpackFloat -> expect - -> toBeSoCloseTo(0.6 *. (low +. high) /. 2.0 +. 0.4 *. (mu +. sigma ** 2.0 /. 2.0), ~digits=0) + -> toBeSoCloseTo(0.6 *. (low +. high) /. 2.0 +. 0.4 *. (mu +. sigma ** 2.0 /. 2.0), ~digits=-1) } ) }) From d582e29e8b310788ff4a2fdda62d5ca94effcc11 Mon Sep 17 00:00:00 2001 From: Quinn Dougherty Date: Thu, 7 Apr 2022 14:33:49 -0400 Subject: [PATCH 11/41] CR comment #1 --- .../squiggle-lang/__tests__/Distributions/Symbolic_test.res | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/squiggle-lang/__tests__/Distributions/Symbolic_test.res b/packages/squiggle-lang/__tests__/Distributions/Symbolic_test.res index 4f17fab2..c2df8674 100644 --- a/packages/squiggle-lang/__tests__/Distributions/Symbolic_test.res +++ b/packages/squiggle-lang/__tests__/Distributions/Symbolic_test.res @@ -167,7 +167,7 @@ describe("Normal distribution with sparklines", () => { -> toEqual(`▁▁▁▁▁▁▁▁▁▁▂▃▅▇███▇▅▃▂`) }) - test("mean=5 cdf", () => { + test("mean=10 cdf", () => { let cdfNormalDistAtMean10 = x => SymbolicDist.Normal.cdf(x, normalDistAtMean10) let sparklineMean10 = fnImage(cdfNormalDistAtMean10, range20Float) Sparklines.create(sparklineMean10, ()) From 72be08a516bf8d85d38e4c247fe933959cf4b38f Mon Sep 17 00:00:00 2001 From: Quinn Dougherty Date: Thu, 7 Apr 2022 18:38:49 -0400 Subject: [PATCH 12/41] CR comments from #192 --- .../__tests__/Distributions/Mixture_test.res | 52 +++++++--------- .../__tests__/Distributions/Samples_test.res | 11 +--- .../__tests__/Distributions/Symbolic_test.res | 62 +++++++------------ .../squiggle-lang/__tests__/TestHelpers.res | 26 ++++++++ packages/squiggle-lang/jest.config.js | 3 + 5 files changed, 78 insertions(+), 76 deletions(-) create mode 100644 packages/squiggle-lang/__tests__/TestHelpers.res diff --git a/packages/squiggle-lang/__tests__/Distributions/Mixture_test.res b/packages/squiggle-lang/__tests__/Distributions/Mixture_test.res index ece229be..2ab1de08 100644 --- a/packages/squiggle-lang/__tests__/Distributions/Mixture_test.res +++ b/packages/squiggle-lang/__tests__/Distributions/Mixture_test.res @@ -1,19 +1,8 @@ open Jest open Expect +open TestHelpers -let env: DistributionOperation.env = { - sampleCount: 10000, - xyPointLength: 1000, -} - -let {toFloat, toDist, toString, toError, fmap} = module(DistributionOperation.Output) -let run = DistributionOperation.run(~env) -let outputMap = fmap(~env) -let toExt: option<'a> => 'a = E.O.toExt( - "Should be impossible to reach (This error is in test file)", -) -let unpackFloat = x => x -> toFloat -> toExt - +// TODO: use Normal.make (etc.), but preferably after the new validation dispatch is in. let mkNormal = (mean, stdev) => GenericDist_Types.Symbolic(#Normal({mean: mean, stdev: stdev})) let mkBeta = (alpha, beta) => GenericDist_Types.Symbolic(#Beta({alpha: alpha, beta: beta})) let mkExponential = rate => GenericDist_Types.Symbolic(#Exponential({rate: rate})) @@ -24,32 +13,35 @@ let mkLognormal = (mu, sigma) => GenericDist_Types.Symbolic(#Lognormal({mu: mu, describe("mixture", () => { testAll("fair mean of two normal distributions", list{(0.0, 1e2), (-1e1, -1e-4), (-1e1, 1e2), (-1e1, 1e1)}, tup => { // should be property let (mean1, mean2) = tup - let theMean = { + let meanValue = { run(Mixture([(mkNormal(mean1, 9e-1), 0.5), (mkNormal(mean2, 9e-1), 0.5)])) -> outputMap(FromDist(ToFloat(#Mean))) } - theMean -> unpackFloat -> expect -> toBeSoCloseTo((mean1 +. mean2) /. 2.0, ~digits=-1) // the .56 is arbitrary? should be 15.0 with a looser tolerance? + meanValue -> unpackFloat -> expect -> toBeSoCloseTo((mean1 +. mean2) /. 2.0, ~digits=-1) }) testAll( "weighted mean of a beta and an exponential", // This would not survive property testing, it was easy for me to find cases that NaN'd out. list{((128.0, 1.0), 2.0), ((2e-1, 64.0), 16.0), ((1e0, 1e0), 64.0)}, tup => { - let (betaParams, rate) = tup - let (alpha, beta) = betaParams - let theMean = { + let ((alpha, beta), rate) = tup + let betaWeight = 0.25 + let exponentialWeight = 0.75 + let meanValue = { run(Mixture( [ - (mkBeta(alpha, beta), 0.25), - (mkExponential(rate), 0.75) + (mkBeta(alpha, beta), betaWeight), + (mkExponential(rate), exponentialWeight) ] )) -> outputMap(FromDist(ToFloat(#Mean))) } - theMean + let betaMean = 1.0 /. (1.0 +. beta /. alpha) + let exponentialMean = 1.0 /. rate + meanValue -> unpackFloat -> expect -> toBeSoCloseTo( - 0.25 *. 1.0 /. (1.0 +. beta /. alpha) +. 0.75 *. 1.0 /. rate, + betaWeight *. betaMean +. exponentialWeight *. exponentialMean, ~digits=-1 ) } @@ -59,17 +51,19 @@ describe("mixture", () => { // Would not survive property tests: very easy to find cases that NaN out. list{((-1e2,1e1), (2e0,1e0)), ((-1e-16,1e-16), (1e-8,1e0)), ((0.0,1e0), (1e0,1e-2))}, tup => { - let (uniformParams, lognormalParams) = tup - let (low, high) = uniformParams - let (mu, sigma) = lognormalParams - let theMean = { - run(Mixture([(mkUniform(low, high), 0.6), (mkLognormal(mu, sigma), 0.4)])) + let ((low, high), (mu, sigma)) = tup + let uniformWeight = 0.6 + let lognormalWeight = 0.4 + let meanValue = { + run(Mixture([(mkUniform(low, high), uniformWeight), (mkLognormal(mu, sigma), lognormalWeight)])) -> outputMap(FromDist(ToFloat(#Mean))) } - theMean + let uniformMean = (low +. high) /. 2.0 + let lognormalMean = mu +. sigma ** 2.0 /. 2.0 + meanValue -> unpackFloat -> expect - -> toBeSoCloseTo(0.6 *. (low +. high) /. 2.0 +. 0.4 *. (mu +. sigma ** 2.0 /. 2.0), ~digits=-1) + -> toBeSoCloseTo(uniformWeight *. uniformMean +. lognormalWeight *. lognormalMean, ~digits=-1) } ) }) diff --git a/packages/squiggle-lang/__tests__/Distributions/Samples_test.res b/packages/squiggle-lang/__tests__/Distributions/Samples_test.res index 170ede1c..6da9efe3 100644 --- a/packages/squiggle-lang/__tests__/Distributions/Samples_test.res +++ b/packages/squiggle-lang/__tests__/Distributions/Samples_test.res @@ -1,19 +1,14 @@ open Jest -open Expect - -let makeTest = (~only=false, str, item1, item2) => - only - ? Only.test(str, () => expect(item1) -> toEqual(item2)) - : test(str, () => expect(item1) -> toEqual(item2)) +open TestHelpers describe("Continuous and discrete splits", () => { makeTest( - "check splits one", + "splits (1)", SampleSet.Internals.T.splitContinuousAndDiscrete([1.432, 1.33455, 2.0]), ([1.432, 1.33455, 2.0], E.FloatFloatMap.empty()), ) makeTest( - "check splits two", + "splits (2)", SampleSet.Internals.T.splitContinuousAndDiscrete([ 1.432, 1.33455, diff --git a/packages/squiggle-lang/__tests__/Distributions/Symbolic_test.res b/packages/squiggle-lang/__tests__/Distributions/Symbolic_test.res index c2df8674..59ab2a8b 100644 --- a/packages/squiggle-lang/__tests__/Distributions/Symbolic_test.res +++ b/packages/squiggle-lang/__tests__/Distributions/Symbolic_test.res @@ -1,34 +1,18 @@ open Jest open Expect +open TestHelpers -let fnImage = (theFn, inps) => Js.Array.map(theFn, inps) - -let env: DistributionOperation.env = { - sampleCount: 100, - xyPointLength: 100, -} - +// TODO: use Normal.make (but preferably after teh new validation dispatch is in) let mkNormal = (mean, stdev) => GenericDist_Types.Symbolic(#Normal({mean: mean, stdev: stdev})) -let {toFloat, toDist, toString, toError, fmap} = module(DistributionOperation.Output) -let run = DistributionOperation.run(~env) -let outputMap = fmap(~env) -let toExtFloat: option => float = E.O.toExt( - "Should be impossible to reach (This error is in test file)", -) -let toExtDist: option => GenericDist_Types.genericDist = E.O.toExt( - "Should be impossible to reach (This error is in a test file)", -) -let unpackFloat = x => x -> toFloat -> toExtFloat -let unpackDist = y => y -> toDist -> toExtDist describe("(Symbolic) normalize", () => { - testAll("has no impact on normal distributions", list{-1e8, -16.0, -1e-2, 0.0, 1e-4, 32.0, 1e16}, mean => { - let theNormal = mkNormal(mean, 2.0) - let theNormalized = run(FromDist(ToDist(Normalize), theNormal)) - theNormalized + testAll("has no impact on normal distributions", list{-1e8, -1e-2, 0.0, 1e-4, 1e16}, mean => { + let normalValue = mkNormal(mean, 2.0) + let normalizedValue = run(FromDist(ToDist(Normalize), normalValue)) + normalizedValue -> unpackDist -> expect - -> toEqual(theNormal) + -> toEqual(normalValue) }) }) @@ -55,13 +39,13 @@ describe("(Symbolic) mean", () => { }) testAll("of exponential distributions", list{1e-7, 2.0, 10.0, 100.0}, rate => { - let theMean = run(FromDist(ToFloat(#Mean), GenericDist_Types.Symbolic(#Exponential({rate: rate})))) - theMean -> unpackFloat -> expect -> toBeCloseTo(1.0 /. rate) // https://en.wikipedia.org/wiki/Exponential_distribution#Mean,_variance,_moments,_and_median + let meanValue = run(FromDist(ToFloat(#Mean), GenericDist_Types.Symbolic(#Exponential({rate: rate})))) + meanValue -> unpackFloat -> expect -> toBeCloseTo(1.0 /. rate) // https://en.wikipedia.org/wiki/Exponential_distribution#Mean,_variance,_moments,_and_median }) test("of a cauchy distribution", () => { - let theMean = run(FromDist(ToFloat(#Mean), GenericDist_Types.Symbolic(#Cauchy({local: 1.0, scale: 1.0})))) - theMean + let meanValue = run(FromDist(ToFloat(#Mean), GenericDist_Types.Symbolic(#Cauchy({local: 1.0, scale: 1.0})))) + meanValue -> unpackFloat -> expect -> toBeCloseTo(2.01868297874546) @@ -70,11 +54,11 @@ describe("(Symbolic) mean", () => { testAll("of triangular distributions", list{(1.0,2.0,3.0), (-1e7,-1e-7,1e-7), (-1e-7,1e0,1e7), (-1e-16,0.0,1e-16)}, tup => { let (low, medium, high) = tup - let theMean = run(FromDist( + let meanValue = run(FromDist( ToFloat(#Mean), GenericDist_Types.Symbolic(#Triangular({low: low, medium: medium, high: high})) )) - theMean + meanValue -> unpackFloat -> expect -> toBeCloseTo((low +. medium +. high) /. 3.0) // https://www.statology.org/triangular-distribution/ @@ -83,11 +67,11 @@ describe("(Symbolic) mean", () => { // TODO: nonpositive inputs are SUPPOSED to crash. testAll("of beta distributions", list{(1e-4, 6.4e1), (1.28e2, 1e0), (1e-16, 1e-16), (1e16, 1e16), (-1e4, 1e1), (1e1, -1e4)}, tup => { let (alpha, beta) = tup - let theMean = run(FromDist( + let meanValue = run(FromDist( ToFloat(#Mean), GenericDist_Types.Symbolic(#Beta({alpha: alpha, beta: beta})) )) - theMean + meanValue -> unpackFloat -> expect -> toBeCloseTo(1.0 /. (1.0 +. (beta /. alpha))) // https://en.wikipedia.org/wiki/Beta_distribution#Mean @@ -95,11 +79,11 @@ describe("(Symbolic) mean", () => { // TODO: When we have our theory of validators we won't want this to be NaN but to be an error. test("of beta(0, 0)", () => { - let theMean = run(FromDist( + let meanValue = run(FromDist( ToFloat(#Mean), GenericDist_Types.Symbolic(#Beta({alpha: 0.0, beta: 0.0})) )) - theMean + meanValue -> unpackFloat -> expect -> ExpectJs.toBeFalsy @@ -107,11 +91,11 @@ describe("(Symbolic) mean", () => { testAll("of lognormal distributions", list{(2.0, 4.0), (1e-7, 1e-2), (-1e6, 10.0), (1e3, -1e2), (-1e8, -1e4), (1e2, 1e-5)}, tup => { let (mu, sigma) = tup - let theMean = run(FromDist( + let meanValue = run(FromDist( ToFloat(#Mean), GenericDist_Types.Symbolic(#Lognormal({mu: mu, sigma: sigma})) )) - theMean + meanValue -> unpackFloat -> expect -> toBeCloseTo(Js.Math.exp(mu +. sigma ** 2.0 /. 2.0 )) // https://brilliant.org/wiki/log-normal-distribution/ @@ -119,22 +103,22 @@ describe("(Symbolic) mean", () => { testAll("of uniform distributions", list{(1e-5, 12.345), (-1e4, 1e4), (-1e16, -1e2), (5.3e3, 9e9)}, tup => { let (low, high) = tup - let theMean = run(FromDist( + let meanValue = run(FromDist( ToFloat(#Mean), GenericDist_Types.Symbolic(#Uniform({low: low, high: high})) )) - theMean + meanValue -> unpackFloat -> expect -> toBeCloseTo((low +. high) /. 2.0) // https://en.wikipedia.org/wiki/Continuous_uniform_distribution#Moments }) test("of a float", () => { - let theMean = run(FromDist( + let meanValue = run(FromDist( ToFloat(#Mean), GenericDist_Types.Symbolic(#Float(7.7)) )) - theMean -> unpackFloat -> expect -> toBeCloseTo(7.7) + meanValue -> unpackFloat -> expect -> toBeCloseTo(7.7) }) }) diff --git a/packages/squiggle-lang/__tests__/TestHelpers.res b/packages/squiggle-lang/__tests__/TestHelpers.res new file mode 100644 index 00000000..a61f57d0 --- /dev/null +++ b/packages/squiggle-lang/__tests__/TestHelpers.res @@ -0,0 +1,26 @@ +open Jest +open Expect + +let makeTest = (~only=false, str, item1, item2) => + only + ? Only.test(str, () => expect(item1) -> toEqual(item2)) + : test(str, () => expect(item1) -> toEqual(item2)) + + +let {toFloat, toDist, toString, toError, fmap} = module(DistributionOperation.Output) + +let fnImage = (theFn, inps) => Js.Array.map(theFn, inps) + +let env: DistributionOperation.env = { + sampleCount: 100, + xyPointLength: 100, +} + +let run = DistributionOperation.run(~env) +let outputMap = fmap(~env) +let unreachableInTestFileMessage = "Should be impossible to reach (This error is in test file)" +let toExtFloat: option => float = E.O.toExt(unreachableInTestFileMessage) +let toExtDist: option => GenericDist_Types.genericDist = E.O.toExt(unreachableInTestFileMessage) +// let toExt: option<'a> => 'a = E.O.toExt(unreachableInTestFileMessage) +let unpackFloat = x => x -> toFloat -> toExtFloat +let unpackDist = y => y -> toDist -> toExtDist diff --git a/packages/squiggle-lang/jest.config.js b/packages/squiggle-lang/jest.config.js index 09bf05a8..f539ef30 100644 --- a/packages/squiggle-lang/jest.config.js +++ b/packages/squiggle-lang/jest.config.js @@ -5,4 +5,7 @@ module.exports = { setupFilesAfterEnv: [ "/../../node_modules/bisect_ppx/src/runtime/js/jest.bs.js" ], + testPathIgnorePatterns: [ + "__tests__/TestHelpers.bs.js" + ], }; From 9764a4cab8a799602590c11b5a230f3c7da3f35c Mon Sep 17 00:00:00 2001 From: Quinn Dougherty Date: Thu, 7 Apr 2022 20:13:08 -0400 Subject: [PATCH 13/41] one last CR comment --- .../__tests__/Distributions/Samples_test.res | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Distributions/Samples_test.res b/packages/squiggle-lang/__tests__/Distributions/Samples_test.res index 6da9efe3..db80f9f7 100644 --- a/packages/squiggle-lang/__tests__/Distributions/Samples_test.res +++ b/packages/squiggle-lang/__tests__/Distributions/Samples_test.res @@ -26,16 +26,16 @@ describe("Continuous and discrete splits", () => { E.A.concatMany([sorted, sorted, sorted, sorted]) |> Belt.SortArray.stableSortBy(_, compare) } - let (_, discrete) = SampleSet.Internals.T.splitContinuousAndDiscrete( + let (_, discrete1) = SampleSet.Internals.T.splitContinuousAndDiscrete( makeDuplicatedArray(10), ) - let toArr = discrete |> E.FloatFloatMap.toArray - makeTest("splitMedium at count=10", toArr |> Belt.Array.length, 10) + let toArr1 = discrete1 |> E.FloatFloatMap.toArray + makeTest("splitMedium at count=10", toArr1 |> Belt.Array.length, 10) - let (_c, discrete) = SampleSet.Internals.T.splitContinuousAndDiscrete( + let (_c, discrete2) = SampleSet.Internals.T.splitContinuousAndDiscrete( makeDuplicatedArray(500), ) - let toArr = discrete |> E.FloatFloatMap.toArray - makeTest("splitMedium at count=500", toArr |> Belt.Array.length, 500) + let toArr2 = discrete2 |> E.FloatFloatMap.toArray + makeTest("splitMedium at count=500", toArr2 |> Belt.Array.length, 500) }) From 53f4e565291223935dc3b6fef479be69aeca7e95 Mon Sep 17 00:00:00 2001 From: Sam Nolan Date: Fri, 8 Apr 2022 10:17:01 +1000 Subject: [PATCH 14/41] Implement generic sparklines with tests --- .../GenericDist/GenericDistSparkline_Test.res | 35 +++++++++++++++++++ .../Distributions/GenericDist/GenericDist.res | 5 ++- .../GenericDist/GenericDist.resi | 8 ++++- .../PointSetDist/PointSetDist.res | 16 +++++++++ 4 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 packages/squiggle-lang/__tests__/GenericDist/GenericDistSparkline_Test.res diff --git a/packages/squiggle-lang/__tests__/GenericDist/GenericDistSparkline_Test.res b/packages/squiggle-lang/__tests__/GenericDist/GenericDistSparkline_Test.res new file mode 100644 index 00000000..8c29f7e4 --- /dev/null +++ b/packages/squiggle-lang/__tests__/GenericDist/GenericDistSparkline_Test.res @@ -0,0 +1,35 @@ +open Jest +open Expect + +let env: DistributionOperation.env = { + sampleCount: 100, + xyPointLength: 100, +} + +let normalDist: GenericDist_Types.genericDist = Symbolic(#Normal({mean: 5.0, stdev: 2.0})) +let uniformDist: GenericDist_Types.genericDist = Symbolic(#Uniform({low: 9.0, high: 10.0})) +let betaDist: GenericDist_Types.genericDist = Symbolic(#Beta({alpha: 2.0, beta: 5.0})) +let lognormalDist: GenericDist_Types.genericDist = Symbolic(#Lognormal({mu: 0.0, sigma: 1.0})) +let cauchyDist: GenericDist_Types.genericDist = Symbolic(#Cauchy({local: 1.0, scale: 1.0})) +let triangularDist: GenericDist_Types.genericDist = Symbolic(#Triangular({low: 1.0, medium: 2.0, high: 3.0})) +let exponentialDist: GenericDist_Types.genericDist = Symbolic(#Exponential({rate: 2.0})) + +let runTest = (name: string, dist : GenericDist_Types.genericDist, expected: string) => { + test(name, () => { + let result = GenericDist.toSparkline(~xyPointLength=100, ~sampleCount=100, ~buckets=20, dist) + switch result { + | Ok(sparkline) => expect(sparkline)->toEqual(expected) + | Error(err) => expect("Error")->toEqual(expected) + } + }) +} + +describe("sparkline of generic distribution", () => { + runTest("normal", normalDist, `▁▁▁▁▂▃▄▆▇██▇▆▄▃▂▁▁▁`) + runTest("uniform", uniformDist, `████████████████████`) + runTest("beta", uniformDist, `████████████████████`) + runTest("lognormal", lognormalDist, `█▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁`) + runTest("cauchy", cauchyDist, `▁▁▁▁▁▁▁▁▁██▁▁▁▁▁▁▁▁▁`) + runTest("triangular", triangularDist, `▁▂▃▄▄▅▆▇████▇▆▅▄▄▃▂▁`) + runTest("exponential", exponentialDist, `█▆▄▃▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁`) +}) diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res index f71d9b93..ab2dd63f 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res @@ -49,7 +49,7 @@ let toFloatOperation = ( } } -//Todo: If it's a pointSet, but the xyPointLenght is different from what it has, it should change. +//Todo: If it's a pointSet, but the xyPointLength is different from what it has, it should change. // This is tricky because the case of discrete distributions. // Also, change the outputXYPoints/pointSetDistLength details let toPointSet = (~xyPointLength, ~sampleCount, t): result => { @@ -75,6 +75,9 @@ let toPointSet = (~xyPointLength, ~sampleCount, t): result => + toPointSet(~xyPointLength, ~sampleCount, t) -> E.R2.fmap(PointSetDist.toSparkline(buckets)) + module Truncate = { let trySymbolicSimplification = (leftCutoff, rightCutoff, t: t): option => switch (leftCutoff, rightCutoff, t) { diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi index 46db83a7..dcb929ca 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi @@ -24,6 +24,12 @@ let toPointSet: ( ~sampleCount: int, t, ) => result +let toSparkline: ( + ~xyPointLength: int, + ~sampleCount: int, + ~buckets: int=?, + t, +) => result let truncate: ( t, @@ -59,4 +65,4 @@ let mixture: ( array<(t, float)>, ~scaleMultiplyFn: scaleMultiplyFn, ~pointwiseAddFn: pointwiseAddFn, -) => result \ No newline at end of file +) => result diff --git a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res index 834b244f..7cacd634 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res @@ -168,6 +168,22 @@ let pdf = (f: float, t: t) => { let inv = T.Integral.yToX let cdf = T.Integral.xToY +let diff = (arr: array): array => + Belt.Array.zipBy(arr, Belt.Array.sliceToEnd(arr, 1), (left, right) => right -. left) + +let rec rangeByFloat = (start : float, end: float, step: float) => + start > end ? + [] + : Belt.Array.concat([start], rangeByFloat(start +. step, end, step)) + +@genType +let toSparkline = (buckets: int, t: t ): string => { + let size : float = T.maxX(t) -. T.minX(t) + let stepSize = size /. Belt.Int.toFloat(buckets) + let cdf = rangeByFloat(T.minX(t), T.maxX(t), stepSize) -> Belt.Array.map(val => cdf(val,t)) + Sparklines.create(diff(cdf), ()) +} + let doN = (n, fn) => { let items = Belt.Array.make(n, 0.0) for x in 0 to n - 1 { From bf2f85a8abe6c00d89c7fc0308c7cda7a50d1e23 Mon Sep 17 00:00:00 2001 From: Sam Nolan Date: Fri, 8 Apr 2022 11:02:41 +1000 Subject: [PATCH 15/41] Respond to sparkline PR change requests --- .../GenericDist/GenericDistSparkline_Test.res | 5 ----- .../Distributions/PointSetDist/PointSetDist.res | 11 ++--------- packages/squiggle-lang/src/rescript/Utility/E.res | 8 ++++++++ 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/packages/squiggle-lang/__tests__/GenericDist/GenericDistSparkline_Test.res b/packages/squiggle-lang/__tests__/GenericDist/GenericDistSparkline_Test.res index 8c29f7e4..8b3a8542 100644 --- a/packages/squiggle-lang/__tests__/GenericDist/GenericDistSparkline_Test.res +++ b/packages/squiggle-lang/__tests__/GenericDist/GenericDistSparkline_Test.res @@ -1,11 +1,6 @@ open Jest open Expect -let env: DistributionOperation.env = { - sampleCount: 100, - xyPointLength: 100, -} - let normalDist: GenericDist_Types.genericDist = Symbolic(#Normal({mean: 5.0, stdev: 2.0})) let uniformDist: GenericDist_Types.genericDist = Symbolic(#Uniform({low: 9.0, high: 10.0})) let betaDist: GenericDist_Types.genericDist = Symbolic(#Beta({alpha: 2.0, beta: 5.0})) diff --git a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res index 7cacd634..d5fa99b6 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res @@ -168,20 +168,13 @@ let pdf = (f: float, t: t) => { let inv = T.Integral.yToX let cdf = T.Integral.xToY -let diff = (arr: array): array => - Belt.Array.zipBy(arr, Belt.Array.sliceToEnd(arr, 1), (left, right) => right -. left) - -let rec rangeByFloat = (start : float, end: float, step: float) => - start > end ? - [] - : Belt.Array.concat([start], rangeByFloat(start +. step, end, step)) @genType let toSparkline = (buckets: int, t: t ): string => { let size : float = T.maxX(t) -. T.minX(t) let stepSize = size /. Belt.Int.toFloat(buckets) - let cdf = rangeByFloat(T.minX(t), T.maxX(t), stepSize) -> Belt.Array.map(val => cdf(val,t)) - Sparklines.create(diff(cdf), ()) + let cdfImage = E.A.rangeByFloat(~step=stepSize, T.minX(t), T.maxX(t)) -> Belt.Array.map(val => cdf(val,t)) + Sparklines.create(E.A.diff(cdfImage), ()) } let doN = (n, fn) => { diff --git a/packages/squiggle-lang/src/rescript/Utility/E.res b/packages/squiggle-lang/src/rescript/Utility/E.res index e36b6124..b3119da3 100644 --- a/packages/squiggle-lang/src/rescript/Utility/E.res +++ b/packages/squiggle-lang/src/rescript/Utility/E.res @@ -292,6 +292,14 @@ module A = { let rangeFloat = (~step=1, start, stop) => Belt.Array.rangeBy(start, stop, ~step) |> fmap(Belt.Int.toFloat) + let diff = (arr: array): array => + Belt.Array.zipBy(arr, Belt.Array.sliceToEnd(arr, 1), (left, right) => right -. left) + + let rec rangeByFloat = (~step: float=1.0, start : float, end: float) : array => + start > end ? + [] + : Belt.Array.concat([start], rangeByFloat(~step, start +. step, end)) + // This zips while taking the longest elements of each array. let zipMaxLength = (array1, array2) => { let maxLength = Int.max(length(array1), length(array2)) From a99290ea43f63ff712644300dc1a9f8f2da712ef Mon Sep 17 00:00:00 2001 From: Sam Nolan Date: Fri, 8 Apr 2022 11:09:31 +1000 Subject: [PATCH 16/41] Rename rangeByFloat to rangeFloat --- .../rescript/Distributions/PointSetDist/PointSetDist.res | 2 +- packages/squiggle-lang/src/rescript/Utility/E.res | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res index d5fa99b6..e4e443fe 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res @@ -173,7 +173,7 @@ let cdf = T.Integral.xToY let toSparkline = (buckets: int, t: t ): string => { let size : float = T.maxX(t) -. T.minX(t) let stepSize = size /. Belt.Int.toFloat(buckets) - let cdfImage = E.A.rangeByFloat(~step=stepSize, T.minX(t), T.maxX(t)) -> Belt.Array.map(val => cdf(val,t)) + let cdfImage = E.A.rangeFloat(~step=stepSize, T.minX(t), T.maxX(t)) -> Belt.Array.map(val => cdf(val,t)) Sparklines.create(E.A.diff(cdfImage), ()) } diff --git a/packages/squiggle-lang/src/rescript/Utility/E.res b/packages/squiggle-lang/src/rescript/Utility/E.res index b3119da3..30b48881 100644 --- a/packages/squiggle-lang/src/rescript/Utility/E.res +++ b/packages/squiggle-lang/src/rescript/Utility/E.res @@ -289,16 +289,14 @@ module A = { )) |> Rationale.Result.return } - let rangeFloat = (~step=1, start, stop) => - Belt.Array.rangeBy(start, stop, ~step) |> fmap(Belt.Int.toFloat) let diff = (arr: array): array => Belt.Array.zipBy(arr, Belt.Array.sliceToEnd(arr, 1), (left, right) => right -. left) - let rec rangeByFloat = (~step: float=1.0, start : float, end: float) : array => + let rec rangeFloat = (~step: float=1.0, start : float, end: float) : array => start > end ? [] - : Belt.Array.concat([start], rangeByFloat(~step, start +. step, end)) + : Belt.Array.concat([start], rangeFloat(~step, start +. step, end)) // This zips while taking the longest elements of each array. let zipMaxLength = (array1, array2) => { From 5a2c4c8aec60278ecaf9e1b8e54b3a2db07ef8de Mon Sep 17 00:00:00 2001 From: Sam Nolan Date: Fri, 8 Apr 2022 11:17:56 +1000 Subject: [PATCH 17/41] Fix build error in test (rangeFloat) --- packages/squiggle-lang/__tests__/Symbolic_test.res | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/squiggle-lang/__tests__/Symbolic_test.res b/packages/squiggle-lang/__tests__/Symbolic_test.res index 8ec3be22..eb953743 100644 --- a/packages/squiggle-lang/__tests__/Symbolic_test.res +++ b/packages/squiggle-lang/__tests__/Symbolic_test.res @@ -22,7 +22,7 @@ describe("Normal distribution with sparklines", () => { let normalDistAtMean5: SymbolicDistTypes.normal = {mean: 5.0, stdev: 2.0} let normalDistAtMean10: SymbolicDistTypes.normal = {mean: 10.0, stdev: 2.0} - let range20Float = E.A.rangeFloat(0, 20) // [0.0,1.0,2.0,3.0,4.0,...19.0,] + let range20Float = E.A.rangeFloat(0.0, 20.0) // [0.0,1.0,2.0,3.0,4.0,...19.0,] let pdfNormalDistAtMean5 = x => Normal.pdf(x, normalDistAtMean5) let sparklineMean5 = pdfImage(pdfNormalDistAtMean5, range20Float) From d6e18b1c4fd69e0ed3d11b632e0663f99de840cc Mon Sep 17 00:00:00 2001 From: Sam Nolan Date: Fri, 8 Apr 2022 16:51:38 +1000 Subject: [PATCH 18/41] Respond to Ozzie's PR comments --- .../GenericDist/GenericDistSparkline_Test.res | 24 +++++++------------ .../GenericDist/GenericDist_Fixtures.res | 11 +++++++++ .../GenericDist/GenericOperation__Test.res | 5 +--- .../__tests__/Reducer/Reducer_TestHelpers.res | 3 --- .../squiggle-lang/__tests__/Symbolic_test.res | 6 ++--- packages/squiggle-lang/jest.config.js | 1 + .../Distributions/GenericDist/GenericDist.res | 6 +++-- .../GenericDist/GenericDist.resi | 1 - .../PointSetDist/PointSetDist.res | 10 -------- .../squiggle-lang/src/rescript/Utility/E.res | 13 +++++----- 10 files changed, 35 insertions(+), 45 deletions(-) create mode 100644 packages/squiggle-lang/__tests__/GenericDist/GenericDist_Fixtures.res diff --git a/packages/squiggle-lang/__tests__/GenericDist/GenericDistSparkline_Test.res b/packages/squiggle-lang/__tests__/GenericDist/GenericDistSparkline_Test.res index 8b3a8542..d2117936 100644 --- a/packages/squiggle-lang/__tests__/GenericDist/GenericDistSparkline_Test.res +++ b/packages/squiggle-lang/__tests__/GenericDist/GenericDistSparkline_Test.res @@ -1,17 +1,11 @@ open Jest open Expect -let normalDist: GenericDist_Types.genericDist = Symbolic(#Normal({mean: 5.0, stdev: 2.0})) -let uniformDist: GenericDist_Types.genericDist = Symbolic(#Uniform({low: 9.0, high: 10.0})) -let betaDist: GenericDist_Types.genericDist = Symbolic(#Beta({alpha: 2.0, beta: 5.0})) -let lognormalDist: GenericDist_Types.genericDist = Symbolic(#Lognormal({mu: 0.0, sigma: 1.0})) -let cauchyDist: GenericDist_Types.genericDist = Symbolic(#Cauchy({local: 1.0, scale: 1.0})) -let triangularDist: GenericDist_Types.genericDist = Symbolic(#Triangular({low: 1.0, medium: 2.0, high: 3.0})) -let exponentialDist: GenericDist_Types.genericDist = Symbolic(#Exponential({rate: 2.0})) +let {normalDist, uniformDist, betaDist, lognormalDist, cauchyDist, triangularDist, exponentialDist} = module(GenericDist_Fixtures) let runTest = (name: string, dist : GenericDist_Types.genericDist, expected: string) => { test(name, () => { - let result = GenericDist.toSparkline(~xyPointLength=100, ~sampleCount=100, ~buckets=20, dist) + let result = GenericDist.toSparkline(~sampleCount=100, ~buckets=20, dist) switch result { | Ok(sparkline) => expect(sparkline)->toEqual(expected) | Error(err) => expect("Error")->toEqual(expected) @@ -20,11 +14,11 @@ let runTest = (name: string, dist : GenericDist_Types.genericDist, expected: str } describe("sparkline of generic distribution", () => { - runTest("normal", normalDist, `▁▁▁▁▂▃▄▆▇██▇▆▄▃▂▁▁▁`) - runTest("uniform", uniformDist, `████████████████████`) - runTest("beta", uniformDist, `████████████████████`) - runTest("lognormal", lognormalDist, `█▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁`) - runTest("cauchy", cauchyDist, `▁▁▁▁▁▁▁▁▁██▁▁▁▁▁▁▁▁▁`) - runTest("triangular", triangularDist, `▁▂▃▄▄▅▆▇████▇▆▅▄▄▃▂▁`) - runTest("exponential", exponentialDist, `█▆▄▃▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁`) + runTest("normal", normalDist, `▁▃▄▅▆▇████████▇▆▅▄▃▁`) + runTest("uniform", uniformDist, `▁██▁`) + runTest("beta", betaDist, `▁▅▇█████████▇▇▆▅▄▃▂▁`) + runTest("lognormal", lognormalDist, `▁▇████▇▇▆▆▅▄▄▃▃▂▂▁▁▁`) + runTest("cauchy", cauchyDist, `▁▁▁▂▄▅▆▇████▇▆▅▄▂▁▁▁`) + runTest("triangular", triangularDist, `▁▃▄▅▆▆▇██████▇▆▆▅▄▃▁`) + runTest("exponential", exponentialDist, `███▇▇▆▆▆▅▅▄▄▃▃▃▂▂▁▁▁`) }) diff --git a/packages/squiggle-lang/__tests__/GenericDist/GenericDist_Fixtures.res b/packages/squiggle-lang/__tests__/GenericDist/GenericDist_Fixtures.res new file mode 100644 index 00000000..05f0981b --- /dev/null +++ b/packages/squiggle-lang/__tests__/GenericDist/GenericDist_Fixtures.res @@ -0,0 +1,11 @@ +let normalDist5: GenericDist_Types.genericDist = Symbolic(#Normal({mean: 5.0, stdev: 2.0})) +let normalDist10: GenericDist_Types.genericDist = Symbolic(#Normal({mean: 10.0, stdev: 2.0})) +let normalDist20: GenericDist_Types.genericDist = Symbolic(#Normal({mean: 20.0, stdev: 2.0})) +let normalDist: GenericDist_Types.genericDist = normalDist5 + +let betaDist: GenericDist_Types.genericDist = Symbolic(#Beta({alpha: 2.0, beta: 5.0})) +let lognormalDist: GenericDist_Types.genericDist = Symbolic(#Lognormal({mu: 0.0, sigma: 1.0})) +let cauchyDist: GenericDist_Types.genericDist = Symbolic(#Cauchy({local: 1.0, scale: 1.0})) +let triangularDist: GenericDist_Types.genericDist = Symbolic(#Triangular({low: 1.0, medium: 2.0, high: 3.0})) +let exponentialDist: GenericDist_Types.genericDist = Symbolic(#Exponential({rate: 2.0})) +let uniformDist: GenericDist_Types.genericDist = Symbolic(#Uniform({low: 9.0, high: 10.0})) diff --git a/packages/squiggle-lang/__tests__/GenericDist/GenericOperation__Test.res b/packages/squiggle-lang/__tests__/GenericDist/GenericOperation__Test.res index dc456865..c936e0bd 100644 --- a/packages/squiggle-lang/__tests__/GenericDist/GenericOperation__Test.res +++ b/packages/squiggle-lang/__tests__/GenericDist/GenericOperation__Test.res @@ -6,11 +6,8 @@ let env: DistributionOperation.env = { xyPointLength: 100, } -let normalDist5: GenericDist_Types.genericDist = Symbolic(#Normal({mean: 5.0, stdev: 2.0})) -let normalDist10: GenericDist_Types.genericDist = Symbolic(#Normal({mean: 10.0, stdev: 2.0})) -let normalDist20: GenericDist_Types.genericDist = Symbolic(#Normal({mean: 20.0, stdev: 2.0})) -let uniformDist: GenericDist_Types.genericDist = Symbolic(#Uniform({low: 9.0, high: 10.0})) +let {normalDist5, normalDist10, normalDist20, uniformDist} = module(GenericDist_Fixtures) let {toFloat, toDist, toString, toError} = module(DistributionOperation.Output) let {run} = module(DistributionOperation) let {fmap} = module(DistributionOperation.Output) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_TestHelpers.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_TestHelpers.res index 7029e2ff..65f689cc 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_TestHelpers.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_TestHelpers.res @@ -9,6 +9,3 @@ let expectParseToBe = (expr: string, answer: string) => let expectEvalToBe = (expr: string, answer: string) => Reducer.eval(expr)->ExpressionValue.toStringResult->expect->toBe(answer) - -// Current configuration does not ignore this file so we have to have a test -test("test helpers", () => expect(1)->toBe(1)) diff --git a/packages/squiggle-lang/__tests__/Symbolic_test.res b/packages/squiggle-lang/__tests__/Symbolic_test.res index eb953743..058a5528 100644 --- a/packages/squiggle-lang/__tests__/Symbolic_test.res +++ b/packages/squiggle-lang/__tests__/Symbolic_test.res @@ -22,12 +22,12 @@ describe("Normal distribution with sparklines", () => { let normalDistAtMean5: SymbolicDistTypes.normal = {mean: 5.0, stdev: 2.0} let normalDistAtMean10: SymbolicDistTypes.normal = {mean: 10.0, stdev: 2.0} - let range20Float = E.A.rangeFloat(0.0, 20.0) // [0.0,1.0,2.0,3.0,4.0,...19.0,] + let range20Float = E.A.Floats.range(0.0, 20.0, 20) // [0.0,1.0,2.0,3.0,4.0,...19.0,] let pdfNormalDistAtMean5 = x => Normal.pdf(x, normalDistAtMean5) let sparklineMean5 = pdfImage(pdfNormalDistAtMean5, range20Float) - makeTest("mean=5", Sparklines.create(sparklineMean5, ()), `▁▂▃▅███▅▃▂▁▁▁▁▁▁▁▁▁▁▁`) + makeTest("mean=5", Sparklines.create(sparklineMean5, ()), `▁▂▃▆██▇▅▂▁▁▁▁▁▁▁▁▁▁▁`) let sparklineMean15 = normalDistAtMean5 -> parameterWiseAdditionHelper(normalDistAtMean10) -> pdfImage(range20Float) - makeTest("parameter-wise addition of two normal distributions", Sparklines.create(sparklineMean15, ()), `▁▁▁▁▁▁▁▁▁▁▂▃▅▇███▇▅▃▂`) + makeTest("parameter-wise addition of two normal distributions", Sparklines.create(sparklineMean15, ()), `▁▁▁▁▁▁▁▁▁▂▃▄▆███▇▅▄▂`) }) diff --git a/packages/squiggle-lang/jest.config.js b/packages/squiggle-lang/jest.config.js index 09bf05a8..a44cd302 100644 --- a/packages/squiggle-lang/jest.config.js +++ b/packages/squiggle-lang/jest.config.js @@ -2,6 +2,7 @@ module.exports = { preset: 'ts-jest', testEnvironment: 'node', + testPathIgnorePatterns: [".*Fixtures.bs.js", "/node_modules/", ".*Helpers.bs.js"], setupFilesAfterEnv: [ "/../../node_modules/bisect_ppx/src/runtime/js/jest.bs.js" ], diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res index ab2dd63f..f3f8402a 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res @@ -75,8 +75,10 @@ let toPointSet = (~xyPointLength, ~sampleCount, t): result => - toPointSet(~xyPointLength, ~sampleCount, t) -> E.R2.fmap(PointSetDist.toSparkline(buckets)) +let toSparkline = (~sampleCount: int, ~buckets: int = 20, t: t) : result => + toPointSet(~xyPointLength=buckets, ~sampleCount, t) + -> E.R.bind(x => x -> PointSetDist.T.toContinuous -> E.O2.toResult(GenericDist_Types.Other("Could not convert to continuous"))) + -> E.R2.fmap(c => Sparklines.create(Continuous.getShape(c).ys, ())) module Truncate = { let trySymbolicSimplification = (leftCutoff, rightCutoff, t: t): option => diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi index dcb929ca..c37385e4 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi @@ -25,7 +25,6 @@ let toPointSet: ( t, ) => result let toSparkline: ( - ~xyPointLength: int, ~sampleCount: int, ~buckets: int=?, t, diff --git a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res index e4e443fe..15186e0b 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res @@ -168,15 +168,6 @@ let pdf = (f: float, t: t) => { let inv = T.Integral.yToX let cdf = T.Integral.xToY - -@genType -let toSparkline = (buckets: int, t: t ): string => { - let size : float = T.maxX(t) -. T.minX(t) - let stepSize = size /. Belt.Int.toFloat(buckets) - let cdfImage = E.A.rangeFloat(~step=stepSize, T.minX(t), T.maxX(t)) -> Belt.Array.map(val => cdf(val,t)) - Sparklines.create(E.A.diff(cdfImage), ()) -} - let doN = (n, fn) => { let items = Belt.Array.make(n, 0.0) for x in 0 to n - 1 { @@ -200,7 +191,6 @@ let isFloat = (t: t) => let sampleNRendered = (n, dist) => { let integralCache = T.Integral.get(dist) let distWithUpdatedIntegralCache = T.updateIntegralCache(Some(integralCache), dist) - doN(n, () => sample(distWithUpdatedIntegralCache)) } diff --git a/packages/squiggle-lang/src/rescript/Utility/E.res b/packages/squiggle-lang/src/rescript/Utility/E.res index 30b48881..0411bf3c 100644 --- a/packages/squiggle-lang/src/rescript/Utility/E.res +++ b/packages/squiggle-lang/src/rescript/Utility/E.res @@ -101,6 +101,7 @@ module O2 = { let default = (a, b) => O.default(b, a) let toExn = (a, b) => O.toExn(b, a) let fmap = (a, b) => O.fmap(b, a) + let toResult = (a, b) => O.toResult(b, a) } /* Functions */ @@ -178,6 +179,7 @@ module R = { module R2 = { let fmap = (a,b) => R.fmap(b,a) + let bind = (a, b) => R.bind(b, a) } let safe_fn_of_string = (fn, s: string): option<'a> => @@ -290,13 +292,6 @@ module A = { |> Rationale.Result.return } - let diff = (arr: array): array => - Belt.Array.zipBy(arr, Belt.Array.sliceToEnd(arr, 1), (left, right) => right -. left) - - let rec rangeFloat = (~step: float=1.0, start : float, end: float) : array => - start > end ? - [] - : Belt.Array.concat([start], rangeFloat(~step, start +. step, end)) // This zips while taking the longest elements of each array. let zipMaxLength = (array1, array2) => { @@ -448,6 +443,10 @@ module A = { let mean = a => sum(a) /. (Array.length(a) |> float_of_int) let random = Js.Math.random_int + let diff = (arr: array): array => + Belt.Array.zipBy(arr, Belt.Array.sliceToEnd(arr, 1), (left, right) => right -. left) + + exception RangeError(string) let range = (min: float, max: float, n: int): array => switch n { From b8d07bd8a4f9ee956ce78111f72fde4b1a05c153 Mon Sep 17 00:00:00 2001 From: Sam Nolan Date: Fri, 8 Apr 2022 16:59:15 +1000 Subject: [PATCH 19/41] Add explaining comment to diff --- packages/squiggle-lang/src/rescript/Utility/E.res | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/squiggle-lang/src/rescript/Utility/E.res b/packages/squiggle-lang/src/rescript/Utility/E.res index 0411bf3c..8e7ec492 100644 --- a/packages/squiggle-lang/src/rescript/Utility/E.res +++ b/packages/squiggle-lang/src/rescript/Utility/E.res @@ -443,6 +443,8 @@ module A = { let mean = a => sum(a) /. (Array.length(a) |> float_of_int) let random = Js.Math.random_int + // Gives an array with all the differences between values + // diff([1,5,3,7]) = [4,-2,4] let diff = (arr: array): array => Belt.Array.zipBy(arr, Belt.Array.sliceToEnd(arr, 1), (left, right) => right -. left) From 0fa954ae634025a20bc3b907d301dc6d98a54829 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Fri, 8 Apr 2022 08:44:04 -0400 Subject: [PATCH 20/41] Improves sparklines by integrating them more deeply to the codebase --- .../GenericDist/GenericDistSparkline_Test.res | 16 ++++++++-------- .../DistributionOperation.res | 6 +++++- .../Distributions/GenericDist/GenericDist.res | 18 ++++++++++++------ .../Distributions/GenericDist/GenericDist.resi | 12 +++++------- .../GenericDist/GenericDist_Types.res | 4 ++++ .../PointSetDist/PointSetDist.res | 5 +++++ .../SymbolicDist/SymbolicDist.res | 4 ++-- .../squiggle-lang/src/rescript/Utility/E.res | 6 ++++++ 8 files changed, 47 insertions(+), 24 deletions(-) diff --git a/packages/squiggle-lang/__tests__/GenericDist/GenericDistSparkline_Test.res b/packages/squiggle-lang/__tests__/GenericDist/GenericDistSparkline_Test.res index d2117936..5aa72004 100644 --- a/packages/squiggle-lang/__tests__/GenericDist/GenericDistSparkline_Test.res +++ b/packages/squiggle-lang/__tests__/GenericDist/GenericDistSparkline_Test.res @@ -5,7 +5,7 @@ let {normalDist, uniformDist, betaDist, lognormalDist, cauchyDist, triangularDis let runTest = (name: string, dist : GenericDist_Types.genericDist, expected: string) => { test(name, () => { - let result = GenericDist.toSparkline(~sampleCount=100, ~buckets=20, dist) + let result = GenericDist.toSparkline(dist, ~sampleCount=100, ~buckets=20, ()) switch result { | Ok(sparkline) => expect(sparkline)->toEqual(expected) | Error(err) => expect("Error")->toEqual(expected) @@ -14,11 +14,11 @@ let runTest = (name: string, dist : GenericDist_Types.genericDist, expected: str } describe("sparkline of generic distribution", () => { - runTest("normal", normalDist, `▁▃▄▅▆▇████████▇▆▅▄▃▁`) - runTest("uniform", uniformDist, `▁██▁`) - runTest("beta", betaDist, `▁▅▇█████████▇▇▆▅▄▃▂▁`) - runTest("lognormal", lognormalDist, `▁▇████▇▇▆▆▅▄▄▃▃▂▂▁▁▁`) - runTest("cauchy", cauchyDist, `▁▁▁▂▄▅▆▇████▇▆▅▄▂▁▁▁`) - runTest("triangular", triangularDist, `▁▃▄▅▆▆▇██████▇▆▆▅▄▃▁`) - runTest("exponential", exponentialDist, `███▇▇▆▆▆▅▅▄▄▃▃▃▂▂▁▁▁`) + runTest("normal", normalDist, `▁▁▁▁▁▂▄▆▇██▇▆▄▂▁▁▁▁▁`) + runTest("uniform", uniformDist, `████████████████████`) + runTest("beta", betaDist, `▁▄▇████▇▆▅▄▃▃▂▁▁▁▁▁▁`) + runTest("lognormal", lognormalDist, `▁█▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁`) + runTest("cauchy", cauchyDist, `▁▁▁▁▁▁▁▁▁██▁▁▁▁▁▁▁▁▁`) + runTest("triangular", triangularDist, `▁▁▂▃▄▅▆▇████▇▆▅▄▃▂▁▁`) + runTest("exponential", exponentialDist, `█▅▄▂▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁`) }) diff --git a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res index 351389ae..4b111c97 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res +++ b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res @@ -114,6 +114,10 @@ let rec run = (~env, functionCallInfo: functionCallInfo): outputType => { ->E.R2.fmap(r => Float(r)) ->OutputLocal.fromResult | ToString => dist->GenericDist.toString->String + | ToSparkline(buckets) => + GenericDist.toSparkline(dist, ~sampleCount, ~buckets, ()) + ->E.R2.fmap(r => String(r)) + ->OutputLocal.fromResult | ToDist(Inspect) => { Js.log2("Console log requested: ", dist) Dist(dist) @@ -127,7 +131,7 @@ let rec run = (~env, functionCallInfo: functionCallInfo): outputType => { dist->GenericDist.sampleN(n)->E.R2.fmap(r => Dist(SampleSet(r)))->OutputLocal.fromResult | ToDist(ToPointSet) => dist - ->GenericDist.toPointSet(~xyPointLength, ~sampleCount) + ->GenericDist.toPointSet(~xyPointLength, ~sampleCount, ()) ->E.R2.fmap(r => Dist(PointSet(r))) ->OutputLocal.fromResult | ToDistCombination(Algebraic, _, #Float(_)) => GenDistError(NotYetImplemented) diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res index f3f8402a..58366a77 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res @@ -52,10 +52,16 @@ let toFloatOperation = ( //Todo: If it's a pointSet, but the xyPointLength is different from what it has, it should change. // This is tricky because the case of discrete distributions. // Also, change the outputXYPoints/pointSetDistLength details -let toPointSet = (~xyPointLength, ~sampleCount, t): result => { +let toPointSet = ( + t, + ~xyPointLength, + ~sampleCount, + ~xSelection: GenericDist_Types.Operation.pointsetXSelection=#ByWeight, + unit, +): result => { switch (t: t) { | PointSet(pointSet) => Ok(pointSet) - | Symbolic(r) => Ok(SymbolicDist.T.toPointSetDist(xyPointLength, r)) + | Symbolic(r) => Ok(SymbolicDist.T.toPointSetDist(~xSelection, xyPointLength, r)) | SampleSet(r) => { let response = SampleSet.toPointSetDist( ~samples=r, @@ -75,10 +81,10 @@ let toPointSet = (~xyPointLength, ~sampleCount, t): result => - toPointSet(~xyPointLength=buckets, ~sampleCount, t) - -> E.R.bind(x => x -> PointSetDist.T.toContinuous -> E.O2.toResult(GenericDist_Types.Other("Could not convert to continuous"))) - -> E.R2.fmap(c => Sparklines.create(Continuous.getShape(c).ys, ())) +let toSparkline = (t: t, ~sampleCount: int, ~buckets: int=20, unit): result => + t + ->toPointSet(~xSelection=#Linear, ~xyPointLength=buckets, ~sampleCount, ()) + ->E.R.bind(r => r->PointSetDist.toSparkline->E.R2.errMap(r => Error(GenericDist_Types.Other(r)))) module Truncate = { let trySymbolicSimplification = (leftCutoff, rightCutoff, t: t): option => diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi index c37385e4..5fa24de9 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi @@ -20,22 +20,20 @@ let toFloatOperation: ( ) => result let toPointSet: ( + t, ~xyPointLength: int, ~sampleCount: int, - t, + ~xSelection: GenericDist_Types.Operation.pointsetXSelection=?, + unit, ) => result -let toSparkline: ( - ~sampleCount: int, - ~buckets: int=?, - t, -) => result +let toSparkline: (t, ~sampleCount: int, ~buckets: int=?, unit) => result let truncate: ( t, ~toPointSetFn: toPointSetFn, ~leftCutoff: option=?, ~rightCutoff: option=?, - unit + unit, ) => result let algebraicCombination: ( diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res index 43ce5d74..ec8374b2 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res @@ -41,6 +41,8 @@ module Operation = { | #Sample ] + type pointsetXSelection = [#Linear | #ByWeight] + type toDist = | Normalize | ToPointSet @@ -55,6 +57,7 @@ module Operation = { | ToDist(toDist) | ToDistCombination(direction, arithmeticOperation, [#Dist(genericDist) | #Float(float)]) | ToString + | ToSparkline(int) type singleParamaterFunction = | FromDist(fromDist) @@ -78,6 +81,7 @@ module Operation = { | ToDist(Truncate(_, _)) => `truncate` | ToDist(Inspect) => `inspect` | ToString => `toString` + | ToSparkline(n) => `toSparkline(${E.I.toString(n)})` | ToDistCombination(Algebraic, _, _) => `algebraic` | ToDistCombination(Pointwise, _, _) => `pointwise` } diff --git a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res index 15186e0b..8224f4cb 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res @@ -202,3 +202,8 @@ let operate = (distToFloatOp: Operation.distToFloatOperation, s): float => | #Sample => sample(s) | #Mean => T.mean(s) } + +let toSparkline = (t: t) => + T.toContinuous(t) + ->E.O2.toResult("toContinous Error: Could not convert into continuous distribution") + ->E.R2.fmap(r => Continuous.getShape(r).ys->Sparklines.create()) \ No newline at end of file diff --git a/packages/squiggle-lang/src/rescript/Distributions/SymbolicDist/SymbolicDist.res b/packages/squiggle-lang/src/rescript/Distributions/SymbolicDist/SymbolicDist.res index cd4132b3..3c757d54 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/SymbolicDist/SymbolicDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/SymbolicDist/SymbolicDist.res @@ -346,11 +346,11 @@ module T = { | _ => #NoSolution } - let toPointSetDist = (sampleCount, d: symbolicDist): PointSetTypes.pointSetDist => + let toPointSetDist = (~xSelection=#ByWeight, sampleCount, d: symbolicDist): PointSetTypes.pointSetDist => switch d { | #Float(v) => Discrete(Discrete.make(~integralSumCache=Some(1.0), {xs: [v], ys: [1.0]})) | _ => - let xs = interpolateXs(~xSelection=#ByWeight, d, sampleCount) + let xs = interpolateXs(~xSelection, d, sampleCount) let ys = xs |> E.A.fmap(x => pdf(x, d)) Continuous(Continuous.make(~integralSumCache=Some(1.0), {xs: xs, ys: ys})) } diff --git a/packages/squiggle-lang/src/rescript/Utility/E.res b/packages/squiggle-lang/src/rescript/Utility/E.res index 8e7ec492..01dbde7d 100644 --- a/packages/squiggle-lang/src/rescript/Utility/E.res +++ b/packages/squiggle-lang/src/rescript/Utility/E.res @@ -180,6 +180,12 @@ module R = { module R2 = { let fmap = (a,b) => R.fmap(b,a) let bind = (a, b) => R.bind(b, a) + + //Converts result type to change error type only + let errMap = (a, map) => switch(a){ + | Ok(r) => Ok(r) + | Error(e) => map(e) + } } let safe_fn_of_string = (fn, s: string): option<'a> => From 837088a9c6ba50facc54dc7b59fa9d55b8f86a1d Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Fri, 8 Apr 2022 08:53:37 -0400 Subject: [PATCH 21/41] Refactored tests to use GenericOperation --- .../GenericDist/GenericDistSparkline_Test.res | 24 ------- .../GenericDist/GenericOperation__Test.res | 65 ++++++++++++++++++- 2 files changed, 63 insertions(+), 26 deletions(-) delete mode 100644 packages/squiggle-lang/__tests__/GenericDist/GenericDistSparkline_Test.res diff --git a/packages/squiggle-lang/__tests__/GenericDist/GenericDistSparkline_Test.res b/packages/squiggle-lang/__tests__/GenericDist/GenericDistSparkline_Test.res deleted file mode 100644 index 5aa72004..00000000 --- a/packages/squiggle-lang/__tests__/GenericDist/GenericDistSparkline_Test.res +++ /dev/null @@ -1,24 +0,0 @@ -open Jest -open Expect - -let {normalDist, uniformDist, betaDist, lognormalDist, cauchyDist, triangularDist, exponentialDist} = module(GenericDist_Fixtures) - -let runTest = (name: string, dist : GenericDist_Types.genericDist, expected: string) => { - test(name, () => { - let result = GenericDist.toSparkline(dist, ~sampleCount=100, ~buckets=20, ()) - switch result { - | Ok(sparkline) => expect(sparkline)->toEqual(expected) - | Error(err) => expect("Error")->toEqual(expected) - } - }) -} - -describe("sparkline of generic distribution", () => { - runTest("normal", normalDist, `▁▁▁▁▁▂▄▆▇██▇▆▄▂▁▁▁▁▁`) - runTest("uniform", uniformDist, `████████████████████`) - runTest("beta", betaDist, `▁▄▇████▇▆▅▄▃▃▂▁▁▁▁▁▁`) - runTest("lognormal", lognormalDist, `▁█▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁`) - runTest("cauchy", cauchyDist, `▁▁▁▁▁▁▁▁▁██▁▁▁▁▁▁▁▁▁`) - runTest("triangular", triangularDist, `▁▁▂▃▄▅▆▇████▇▆▅▄▃▂▁▁`) - runTest("exponential", exponentialDist, `█▅▄▂▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁`) -}) diff --git a/packages/squiggle-lang/__tests__/GenericDist/GenericOperation__Test.res b/packages/squiggle-lang/__tests__/GenericDist/GenericOperation__Test.res index c936e0bd..be01c87f 100644 --- a/packages/squiggle-lang/__tests__/GenericDist/GenericOperation__Test.res +++ b/packages/squiggle-lang/__tests__/GenericDist/GenericOperation__Test.res @@ -6,8 +6,18 @@ let env: DistributionOperation.env = { xyPointLength: 100, } - -let {normalDist5, normalDist10, normalDist20, uniformDist} = module(GenericDist_Fixtures) +let { + normalDist5, + normalDist10, + normalDist20, + normalDist, + uniformDist, + betaDist, + lognormalDist, + cauchyDist, + triangularDist, + exponentialDist, +} = module(GenericDist_Fixtures) let {toFloat, toDist, toString, toError} = module(DistributionOperation.Output) let {run} = module(DistributionOperation) let {fmap} = module(DistributionOperation.Output) @@ -42,6 +52,57 @@ describe("mixture", () => { }) }) +describe("sparkline", () => { + let runTest = ( + name: string, + dist: GenericDist_Types.genericDist, + expected: DistributionOperation.outputType, + ) => { + test(name, () => { + let result = DistributionOperation.run(~env, FromDist(ToSparkline(20), dist)) + expect(result)->toEqual(expected) + }) + } + + runTest( + "normal", + normalDist, + String(`▁▁▁▁▁▂▄▆▇██▇▆▄▂▁▁▁▁▁`), + ) + + runTest( + "uniform", + uniformDist, + String(`████████████████████`), + ) + + runTest("beta", betaDist, String(`▁▄▇████▇▆▅▄▃▃▂▁▁▁▁▁▁`)) + + runTest( + "lognormal", + lognormalDist, + String(`▁█▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁`), + ) + + runTest( + "cauchy", + cauchyDist, + String(`▁▁▁▁▁▁▁▁▁██▁▁▁▁▁▁▁▁▁`), + ) + + runTest( + "triangular", + triangularDist, + String(`▁▁▂▃▄▅▆▇████▇▆▅▄▃▂▁▁`), + ) + + runTest( + "exponential", + exponentialDist, + String(`█▅▄▂▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁`), + ) +}) + describe("toPointSet", () => { test("on symbolic normal distribution", () => { let result = From 937a8482fdb4e1912303d365a36642e81ca06af5 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Fri, 8 Apr 2022 09:08:49 -0400 Subject: [PATCH 22/41] Added sparkline and toString to ReducerInterface --- .../__tests__/GenericDist/GenericOperation__Test.res | 2 +- .../ReducerInterface_Distribution_test.res | 3 +++ .../DistributionOperation/DistributionOperation.res | 4 ++-- .../Distributions/GenericDist/GenericDist_Types.res | 11 +++++++---- .../ReducerInterface_GenericDistribution.res | 10 ++++++++++ 5 files changed, 23 insertions(+), 7 deletions(-) diff --git a/packages/squiggle-lang/__tests__/GenericDist/GenericOperation__Test.res b/packages/squiggle-lang/__tests__/GenericDist/GenericOperation__Test.res index be01c87f..67659a41 100644 --- a/packages/squiggle-lang/__tests__/GenericDist/GenericOperation__Test.res +++ b/packages/squiggle-lang/__tests__/GenericDist/GenericOperation__Test.res @@ -59,7 +59,7 @@ describe("sparkline", () => { expected: DistributionOperation.outputType, ) => { test(name, () => { - let result = DistributionOperation.run(~env, FromDist(ToSparkline(20), dist)) + let result = DistributionOperation.run(~env, FromDist(ToString(ToSparkline(20)), dist)) expect(result)->toEqual(expected) }) } diff --git a/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_test.res b/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_test.res index 85d80919..096ac360 100644 --- a/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_test.res +++ b/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_test.res @@ -30,6 +30,9 @@ describe("eval on distribution functions", () => { testEval("mean(normal(5,2))", "Ok(5)") testEval("mean(lognormal(1,2))", "Ok(20.085536923187668)") }) + describe("toString", () => { + testEval("toString(normal(5,2))", "Ok('Normal(5,2)')") + }) describe("normalize", () => { testEval("normalize(normal(5,2))", "Ok(Normal(5,2))") }) diff --git a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res index 4b111c97..faf39e27 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res +++ b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res @@ -113,8 +113,8 @@ let rec run = (~env, functionCallInfo: functionCallInfo): outputType => { GenericDist.toFloatOperation(dist, ~toPointSetFn, ~distToFloatOperation) ->E.R2.fmap(r => Float(r)) ->OutputLocal.fromResult - | ToString => dist->GenericDist.toString->String - | ToSparkline(buckets) => + | ToString(ToString) => dist->GenericDist.toString->String + | ToString(ToSparkline(buckets)) => GenericDist.toSparkline(dist, ~sampleCount, ~buckets, ()) ->E.R2.fmap(r => String(r)) ->OutputLocal.fromResult diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res index ec8374b2..cc9f94c9 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res @@ -52,12 +52,15 @@ module Operation = { type toFloatArray = Sample(int) + type toString = + | ToString + | ToSparkline(int) + type fromDist = | ToFloat(toFloat) | ToDist(toDist) | ToDistCombination(direction, arithmeticOperation, [#Dist(genericDist) | #Float(float)]) - | ToString - | ToSparkline(int) + | ToString(toString) type singleParamaterFunction = | FromDist(fromDist) @@ -80,8 +83,8 @@ module Operation = { | ToDist(ToSampleSet(r)) => `toSampleSet(${E.I.toString(r)})` | ToDist(Truncate(_, _)) => `truncate` | ToDist(Inspect) => `inspect` - | ToString => `toString` - | ToSparkline(n) => `toSparkline(${E.I.toString(n)})` + | ToString(ToString) => `toString` + | ToString(ToSparkline(n)) => `toSparkline(${E.I.toString(n)})` | ToDistCombination(Algebraic, _, _) => `algebraic` | ToDistCombination(Pointwise, _, _) => `pointwise` } diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res index 84e0697f..89be2d46 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res @@ -45,6 +45,13 @@ module Helpers = { FromDist(GenericDist_Types.Operation.ToFloat(fnCall), dist)->runGenericOperation->Some } + let toStringFn = ( + fnCall: GenericDist_Types.Operation.toString, + dist: GenericDist_Types.genericDist, + ) => { + FromDist(GenericDist_Types.Operation.ToString(fnCall), dist)->runGenericOperation->Some + } + let toDistFn = (fnCall: GenericDist_Types.Operation.toDist, dist) => { FromDist(GenericDist_Types.Operation.ToDist(fnCall), dist)->runGenericOperation->Some } @@ -119,6 +126,9 @@ let dispatchToGenericOutput = (call: ExpressionValue.functionCall): option< ->SymbolicConstructors.symbolicResultToOutput | ("sample", [EvDistribution(dist)]) => Helpers.toFloatFn(#Sample, dist) | ("mean", [EvDistribution(dist)]) => Helpers.toFloatFn(#Mean, dist) + | ("toString", [EvDistribution(dist)]) => Helpers.toStringFn(ToString, dist) + | ("toSparkline", [EvDistribution(dist)]) => Helpers.toStringFn(ToSparkline(20), dist) + | ("toSparkline", [EvDistribution(dist), EvNumber(n)]) => Helpers.toStringFn(ToSparkline(Belt.Float.toInt(n)), dist) | ("exp", [EvDistribution(a)]) => // https://mathjs.org/docs/reference/functions/exp.html Helpers.twoDiststoDistFn(Algebraic, "pow", GenericDist.fromFloat(Math.e), a)->Some From 6634718ba93096c2fcf5e7a0a1c701bda66a72f4 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Fri, 8 Apr 2022 09:32:48 -0400 Subject: [PATCH 23/41] Cleanup from merge --- .../DistributionOperation_test.res | 25 ------------------- packages/squiggle-lang/jest.config.js | 13 +++++----- 2 files changed, 7 insertions(+), 31 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Distributions/DistributionOperation_test.res b/packages/squiggle-lang/__tests__/Distributions/DistributionOperation_test.res index 3b1219b3..cd22d512 100644 --- a/packages/squiggle-lang/__tests__/Distributions/DistributionOperation_test.res +++ b/packages/squiggle-lang/__tests__/Distributions/DistributionOperation_test.res @@ -29,31 +29,6 @@ let toExt: option<'a> => 'a = E.O.toExt( "Should be impossible to reach (This error is in test file)", ) -describe("normalize", () => { - test("has no impact on normal dist", () => { - let result = run(FromDist(ToDist(Normalize), normalDist5)) - expect(result)->toEqual(Dist(normalDist5)) - }) -}) - -describe("mean", () => { - test("for a normal distribution", () => { - let result = DistributionOperation.run(~env, FromDist(ToFloat(#Mean), normalDist5)) - expect(result)->toEqual(Float(5.0)) - }) -}) - -describe("mixture", () => { - test("on two normal distributions", () => { - let result = - run(Mixture([(normalDist10, 0.5), (normalDist20, 0.5)])) - ->outputMap(FromDist(ToFloat(#Mean))) - ->toFloat - ->toExt - expect(result)->toBeCloseTo(15.28) - }) -}) - describe("sparkline", () => { let runTest = ( name: string, diff --git a/packages/squiggle-lang/jest.config.js b/packages/squiggle-lang/jest.config.js index f5d19afb..3347de7c 100644 --- a/packages/squiggle-lang/jest.config.js +++ b/packages/squiggle-lang/jest.config.js @@ -1,12 +1,13 @@ /** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */ module.exports = { - preset: 'ts-jest', - testEnvironment: 'node', - testPathIgnorePatterns: [".*Fixtures.bs.js", "/node_modules/", ".*Helpers.bs.js"], + preset: "ts-jest", + testEnvironment: "node", setupFilesAfterEnv: [ - "/../../node_modules/bisect_ppx/src/runtime/js/jest.bs.js" + "/../../node_modules/bisect_ppx/src/runtime/js/jest.bs.js", ], testPathIgnorePatterns: [ - "__tests__/TestHelpers.bs.js" - ], + ".*Fixtures.bs.js", + "/node_modules/", + ".*Helpers.bs.js", + ], }; From 7622a9e533126762961ad24db3dad82236708c66 Mon Sep 17 00:00:00 2001 From: Quinn Date: Fri, 8 Apr 2022 14:41:26 -0400 Subject: [PATCH 24/41] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 3ded43c6..13aa5ef7 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # Squiggle +![Packages check](https://github.com/QURIresearch/squiggle/actions/workflows/ci.yaml/badge.svg) This is an experiment DSL/language for making probabilistic estimates. The full story can be found [here](https://www.lesswrong.com/s/rDe8QE5NvXcZYzgZ3). From 57196c568b3b7f191c53f49965c593b4818bea26 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Fri, 8 Apr 2022 14:42:14 -0400 Subject: [PATCH 25/41] Added a bunch of manual functions for DistributionOperation --- packages/squiggle-lang/bsconfig.json | 2 +- packages/squiggle-lang/src/js/index.ts | 190 ++++++++++++++++-- .../DistributionOperation.res | 47 +++++ .../DistributionOperation.resi | 36 ++++ .../GenericDist/GenericDist_Types.res | 75 ++++++- .../Distributions/SampleSetDist/SampleSet.res | 1 + .../src/rescript/TSInterface.res | 14 ++ 7 files changed, 348 insertions(+), 17 deletions(-) create mode 100644 packages/squiggle-lang/src/rescript/TSInterface.res diff --git a/packages/squiggle-lang/bsconfig.json b/packages/squiggle-lang/bsconfig.json index e936eb82..958a3af8 100644 --- a/packages/squiggle-lang/bsconfig.json +++ b/packages/squiggle-lang/bsconfig.json @@ -33,7 +33,7 @@ "gentypeconfig": { "language": "typescript", "module": "commonjs", - "shims": {}, + "shims": {"Js": "Js"}, "debug": { "all": false, "basic": false diff --git a/packages/squiggle-lang/src/js/index.ts b/packages/squiggle-lang/src/js/index.ts index 7856ef6f..5f12bf56 100644 --- a/packages/squiggle-lang/src/js/index.ts +++ b/packages/squiggle-lang/src/js/index.ts @@ -1,17 +1,181 @@ -import {runAll} from '../rescript/ProgramEvaluator.gen'; -import type { Inputs_SamplingInputs_t as SamplingInputs, exportEnv, exportType, exportDistribution} from '../rescript/ProgramEvaluator.gen'; -export type { SamplingInputs, exportEnv, exportDistribution } -export type {t as DistPlus} from '../rescript/OldInterpreter/DistPlus.gen'; +import { runAll } from "../rescript/ProgramEvaluator.gen"; +import type { + Inputs_SamplingInputs_t as SamplingInputs, + exportEnv, + exportType, + exportDistribution, +} from "../rescript/ProgramEvaluator.gen"; +export type { SamplingInputs, exportEnv, exportDistribution }; +export type { t as DistPlus } from "../rescript/OldInterpreter/DistPlus.gen"; +import type { Operation_genericFunctionCallInfo } from "../rescript/Distributions/GenericDist/GenericDist_Types.gen"; +import { genericDist } from "../rescript/TSInterface.gen"; +import { + run as runR, + env, + outputType, +} from "../rescript/Distributions/DistributionOperation/DistributionOperation.gen"; +import { add } from "lodash"; -export let defaultSamplingInputs : SamplingInputs = { - sampleCount : 10000, - outputXYPoints : 10000, - pointDistLength : 1000 +export let defaultSamplingInputs: SamplingInputs = { + sampleCount: 10000, + outputXYPoints: 10000, + pointDistLength: 1000, +}; + +export function run( + squiggleString: string, + samplingInputs?: SamplingInputs, + environment?: exportEnv +): { tag: "Ok"; value: exportType } | { tag: "Error"; value: string } { + let si: SamplingInputs = samplingInputs + ? samplingInputs + : defaultSamplingInputs; + let env: exportEnv = environment ? environment : []; + return runAll(squiggleString, si, env); } -export function run(squiggleString : string, samplingInputs? : SamplingInputs, environment?: exportEnv) : { tag: "Ok"; value: exportType } - | { tag: "Error"; value: string } { - let si : SamplingInputs = samplingInputs ? samplingInputs : defaultSamplingInputs - let env : exportEnv = environment ? environment : [] - return runAll(squiggleString, si, env) +class GenericDist { + t: genericDist; + env: env; + + constructor(t: genericDist, env: env) { + this.t = t; + } + + mean(): outputType { + return runR( + { env: this.env }, + { tag: "FromDist", value: [{ tag: "ToFloat", value: "Mean" }, this.t] } + ); + } + + pdf(n: number): outputType { + return runR( + { env: this.env }, + { + tag: "FromDist", + value: [{ tag: "ToFloat", value: { NAME: "Pdf", VAL: n } }, this.t], + } + ); + } + + cdf(n: number): outputType { + return runR( + { env: this.env }, + { + tag: "FromDist", + value: [{ tag: "ToFloat", value: { NAME: "Pdf", VAL: n } }, this.t], + } + ); + } + + inv(n: number): outputType { + return runR( + { env: this.env }, + { + tag: "FromDist", + value: [{ tag: "ToFloat", value: { NAME: "Pdf", VAL: n } }, this.t], + } + ); + } + + normalize(n: number): outputType { + return runR( + { env: this.env }, + { + tag: "FromDist", + value: [{ tag: "ToDist", value: "Normalize" }, this.t], + } + ); + } + + toPointSet(): outputType { + return runR( + { env: this.env }, + { + tag: "FromDist", + value: [{ tag: "ToDist", value: "ToPointSet" }, this.t], + } + ); + } + + inspect(): outputType { + return runR( + { env: this.env }, + { tag: "FromDist", value: [{ tag: "ToDist", value: "Inspect" }, this.t] } + ); + } + + toSampleSet(n: number): outputType { + return runR( + { env: this.env }, + { + tag: "FromDist", + value: [ + { tag: "ToDist", value: { tag: "ToSampleSet", value: n } }, + this.t, + ], + } + ); + } + + truncate( + left: null | undefined | number, + right: null | undefined | number + ): outputType { + return runR( + { env: this.env }, + { + tag: "FromDist", + value: [ + { tag: "ToDist", value: { tag: "Truncate", value: [left, right] } }, + this.t, + ], + } + ); + } + + toString(): outputType { + return runR( + { env: this.env }, + { + tag: "FromDist", + value: [{ tag: "ToString", value: "ToString" }, this.t], + } + ); + } + + toSparkline(n: number): outputType { + return runR( + { env: this.env }, + { + tag: "FromDist", + value: [ + { tag: "ToString", value: { tag: "ToSparkline", value: n } }, + this.t, + ], + } + ); + } + + add(g2: genericDist): outputType { + return runR( + { env: this.env }, + { + tag: "FromDist", + value: [ + { + tag: "ToDistCombination", + value: [ + { + tag: "ToDistCombination", + value: ["Algebraic", "Add", { NAME: "Dist", VAL: g2 }], + }, + ], + }, + this.t, + ], + } + ); + } } diff --git a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res index 14e7b6c4..1d25f64c 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res +++ b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res @@ -185,3 +185,50 @@ module Output = { newFnCall->E.R2.fmap(run(~env))->OutputLocal.fromResult } } + +module Constructors = { + module UsingDists = { + module C = GenericDist_Types.Constructors.UsingDists + open OutputLocal + type dist = GenericDist_Types.genericDist + type fResult = result + type dResult = result + type sResult = result + + let mean = (~env, dist) => run(~env, C.mean(dist))->toFloatR + let sample = (~env, dist) => run(~env, C.sample(dist))->toFloatR + let cdf = (~env, dist, f) => run(~env, C.cdf(dist, f))->toFloatR + let inv = (~env, dist, f) => run(~env, C.inv(dist, f))->toFloatR + let pdf = (~env, dist, f) => run(~env, C.pdf(dist, f))->toFloatR + let normalize = (~env, dist) => run(~env, C.normalize(dist))->toDistR + let toPointSet = (~env, dist) => run(~env, C.toPointSet(dist))->toDistR + let toSampleSet = (~env, dist, n) => run(~env, C.toSampleSet(dist, n))->toDistR + let truncate = (~env, dist, leftCutoff, rightCutoff) => + run(~env, C.truncate(dist, leftCutoff, rightCutoff))->toDistR + let inspect = (~env, dist) => run(~env, C.inspect(dist))->toDistR + let toString = (~env, dist) => run(~env, C.toString(dist))->toStringR + let toSparkline = (~env, dist, buckets) => run(~env, C.toSparkline(dist, buckets))->toStringR + let algebraicAdd = (~env, dist1, dist2) => run(~env, C.algebraicAdd(dist1, dist2))->toDistR + let algebraicMultiply = (~env, dist1, dist2) => + run(~env, C.algebraicMultiply(dist1, dist2))->toDistR + let algebraicDivide = (~env, dist1, dist2) => + run(~env, C.algebraicDivide(dist1, dist2))->toDistR + let algebraicSubtract = (~env, dist1, dist2) => + run(~env, C.algebraicSubtract(dist1, dist2))->toDistR + let algebraicLogarithm = (~env, dist1, dist2) => + run(~env, C.algebraicLogarithm(dist1, dist2))->toDistR + let algebraicExponentiate = (~env, dist1, dist2) => + run(~env, C.algebraicExponentiate(dist1, dist2))->toDistR + let pointwiseAdd = (~env, dist1, dist2) => run(~env, C.pointwiseAdd(dist1, dist2))->toDistR + let pointwiseMultiply = (~env, dist1, dist2) => + run(~env, C.pointwiseMultiply(dist1, dist2))->toDistR + let pointwiseDivide = (~env, dist1, dist2) => + run(~env, C.pointwiseDivide(dist1, dist2))->toDistR + let pointwiseSubtract = (~env, dist1, dist2) => + run(~env, C.pointwiseSubtract(dist1, dist2))->toDistR + let pointwiseLogarithm = (~env, dist1, dist2) => + run(~env, C.pointwiseSubtract(dist1, dist2))->toDistR + let pointwiseExponentiate = (~env, dist1, dist2) => + run(~env, C.pointwiseSubtract(dist1, dist2))->toDistR + } +} diff --git a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.resi b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.resi index 3c3e132a..e39d5848 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.resi +++ b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.resi @@ -1,14 +1,17 @@ +@genType type env = { sampleCount: int, xyPointLength: int, } +@genType type outputType = | Dist(GenericDist_Types.genericDist) | Float(float) | String(string) | GenDistError(GenericDist_Types.error) +@genType let run: (~env: env, GenericDist_Types.Operation.genericFunctionCallInfo) => outputType let runFromDist: ( ~env: env, @@ -32,3 +35,36 @@ module Output: { let toError: t => option let fmap: (~env: env, t, GenericDist_Types.Operation.singleParamaterFunction) => t } + +module Constructors: { + module UsingDists: { + type dist = GenericDist_Types.genericDist + type fResult = result + type dResult = result + type sResult = result + let mean: (~env: env, dist) => fResult + let sample: (~env: env, dist) => fResult + let cdf: (~env: env, dist, float) => fResult + let inv: (~env: env, dist, float) => fResult + let pdf: (~env: env, dist, float) => fResult + let normalize: (~env: env, dist) => dResult + let toPointSet: (~env: env, dist) => dResult + let toSampleSet: (~env: env, dist, int) => dResult + let truncate: (~env: env, dist, option, option) => dResult + let inspect: (~env: env, dist) => dResult + let toString: (~env: env, dist) => sResult + let toSparkline: (~env: env, dist, int) => sResult + let algebraicAdd: (~env: env, dist, dist) => dResult + let algebraicMultiply: (~env: env, dist, dist) => dResult + let algebraicDivide: (~env: env, dist, dist) => dResult + let algebraicSubtract: (~env: env, dist, dist) => dResult + let algebraicLogarithm: (~env: env, dist, dist) => dResult + let algebraicExponentiate: (~env: env, dist, dist) => dResult + let pointwiseAdd: (~env: env, dist, dist) => dResult + let pointwiseMultiply: (~env: env, dist, dist) => dResult + let pointwiseDivide: (~env: env, dist, dist) => dResult + let pointwiseSubtract: (~env: env, dist, dist) => dResult + let pointwiseLogarithm: (~env: env, dist, dist) => dResult + let pointwiseExponentiate: (~env: env, dist, dist) => dResult + } +} diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res index 0eb64bd7..f472a6e0 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res @@ -3,6 +3,7 @@ type genericDist = | SampleSet(SampleSet.t) | Symbolic(SymbolicDistTypes.symbolicDist) +@genType type error = | NotYetImplemented | Unreachable @@ -52,9 +53,9 @@ module Operation = { type toFloatArray = Sample(int) - type toString = - | ToString - | ToSparkline(int) + type toString = + | ToString + | ToSparkline(int) type fromDist = | ToFloat(toFloat) @@ -66,6 +67,7 @@ module Operation = { | FromDist(fromDist) | FromFloat(fromDist) + @genType type genericFunctionCallInfo = | FromDist(fromDist, genericDist) | FromFloat(fromDist, float) @@ -95,3 +97,70 @@ module Operation = { | Mixture(_) => `mixture` } } + +module Constructors = { + type t = Operation.genericFunctionCallInfo + + module UsingDists = { + let mean = (dist): t => FromDist(ToFloat(#Mean), dist) + let sample = (dist): t => FromDist(ToFloat(#Mean), dist) + let cdf = (dist, f): t => FromDist(ToFloat(#Cdf(f)), dist) + let inv = (dist, f): t => FromDist(ToFloat(#Inv(f)), dist) + let pdf = (dist, f): t => FromDist(ToFloat(#Pdf(f)), dist) + let normalize = (dist): t => FromDist(ToDist(Normalize), dist) + let toPointSet = (dist): t => FromDist(ToDist(ToPointSet), dist) + let toSampleSet = (dist, r): t => FromDist(ToDist(ToSampleSet(r)), dist) + let truncate = (dist, left, right): t => FromDist(ToDist(Truncate(left, right)), dist) + let inspect = (dist): t => FromDist(ToDist(Inspect), 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( + ToDistCombination(Algebraic, #Add, #Dist(dist2)), + dist1, + ) + let algebraicMultiply = (dist1, dist2): t => FromDist( + ToDistCombination(Algebraic, #Multiply, #Dist(dist2)), + dist1, + ) + let algebraicDivide = (dist1, dist2): t => FromDist( + ToDistCombination(Algebraic, #Divide, #Dist(dist2)), + dist1, + ) + let algebraicSubtract = (dist1, dist2): t => FromDist( + ToDistCombination(Algebraic, #Subtract, #Dist(dist2)), + dist1, + ) + let algebraicLogarithm = (dist1, dist2): t => FromDist( + ToDistCombination(Algebraic, #Logarithm, #Dist(dist2)), + dist1, + ) + let algebraicExponentiate = (dist1, dist2): t => FromDist( + ToDistCombination(Algebraic, #Exponentiate, #Dist(dist2)), + dist1, + ) + let pointwiseAdd = (dist1, dist2): t => FromDist( + ToDistCombination(Algebraic, #Add, #Dist(dist2)), + dist1, + ) + let pointwiseMultiply = (dist1, dist2): t => FromDist( + ToDistCombination(Pointwise, #Multiply, #Dist(dist2)), + dist1, + ) + let pointwiseDivide = (dist1, dist2): t => FromDist( + ToDistCombination(Pointwise, #Divide, #Dist(dist2)), + dist1, + ) + let pointwiseSubtract = (dist1, dist2): t => FromDist( + ToDistCombination(Pointwise, #Subtract, #Dist(dist2)), + dist1, + ) + let pointwiseLogarithm = (dist1, dist2): t => FromDist( + ToDistCombination(Pointwise, #Logarithm, #Dist(dist2)), + dist1, + ) + let pointwiseExponentiate = (dist1, dist2): t => FromDist( + ToDistCombination(Pointwise, #Exponentiate, #Dist(dist2)), + dist1, + ) + } +} diff --git a/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSet.res b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSet.res index eebb9efc..3c8f686a 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSet.res +++ b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSet.res @@ -1,3 +1,4 @@ +@genType type t = array // TODO: Refactor to raise correct error when not enough samples diff --git a/packages/squiggle-lang/src/rescript/TSInterface.res b/packages/squiggle-lang/src/rescript/TSInterface.res new file mode 100644 index 00000000..8df300f8 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/TSInterface.res @@ -0,0 +1,14 @@ +@genType +type functionCallInfo = GenericDist_Types.Operation.genericFunctionCallInfo; + +@genType +type env = DistributionOperation.env; + +@genType +type genericDist = GenericDist_Types.genericDist; + +@genType +type error = GenericDist_Types.error; + +@genType +let runDistributionOperation = DistributionOperation.run; \ No newline at end of file From e065a57a665e3c0cedb9588576f92742edb52b26 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Fri, 8 Apr 2022 15:55:04 -0400 Subject: [PATCH 26/41] Added to index.ts --- packages/squiggle-lang/src/js/index.ts | 224 ++++++++++-------- .../DistributionOperation.res | 7 +- .../DistributionOperation.resi | 99 +++++--- .../GenericDist/GenericDist_Types.res | 62 ++++- .../src/rescript/TSInterface.res | 9 +- 5 files changed, 265 insertions(+), 136 deletions(-) diff --git a/packages/squiggle-lang/src/js/index.ts b/packages/squiggle-lang/src/js/index.ts index 5f12bf56..a250c4fc 100644 --- a/packages/squiggle-lang/src/js/index.ts +++ b/packages/squiggle-lang/src/js/index.ts @@ -8,13 +8,39 @@ import type { export type { SamplingInputs, exportEnv, exportDistribution }; export type { t as DistPlus } from "../rescript/OldInterpreter/DistPlus.gen"; import type { Operation_genericFunctionCallInfo } from "../rescript/Distributions/GenericDist/GenericDist_Types.gen"; -import { genericDist } from "../rescript/TSInterface.gen"; import { - run as runR, + genericDist, + resultDist, + resultFloat, + resultString, +} from "../rescript/TSInterface.gen"; +import { env, - outputType, + Constructors_UsingDists_mean, + Constructors_UsingDists_sample, + Constructors_UsingDists_pdf, + Constructors_UsingDists_cdf, + Constructors_UsingDists_inv, + Constructors_UsingDists_normalize, + Constructors_UsingDists_toPointSet, + Constructors_UsingDists_toSampleSet, + Constructors_UsingDists_truncate, + Constructors_UsingDists_inspect, + Constructors_UsingDists_toString, + Constructors_UsingDists_toSparkline, + Constructors_UsingDists_algebraicAdd, + Constructors_UsingDists_algebraicMultiply, + Constructors_UsingDists_algebraicDivide, + Constructors_UsingDists_algebraicSubtract, + Constructors_UsingDists_algebraicLogarithm, + Constructors_UsingDists_algebraicExponentiate, + Constructors_UsingDists_pointwiseAdd, + Constructors_UsingDists_pointwiseMultiply, + Constructors_UsingDists_pointwiseDivide, + Constructors_UsingDists_pointwiseSubtract, + Constructors_UsingDists_pointwiseLogarithm, + Constructors_UsingDists_pointwiseExponentiate, } from "../rescript/Distributions/DistributionOperation/DistributionOperation.gen"; -import { add } from "lodash"; export let defaultSamplingInputs: SamplingInputs = { sampleCount: 10000, @@ -42,140 +68,152 @@ class GenericDist { this.t = t; } - mean(): outputType { - return runR( + mean(): resultFloat { + return Constructors_UsingDists_mean({ env: this.env }, this.t); + } + + sample(): resultFloat { + return Constructors_UsingDists_sample({ env: this.env }, this.t); + } + + pdf(n: number): resultFloat { + return Constructors_UsingDists_pdf({ env: this.env }, this.t, n); + } + + cdf(n: number): resultFloat { + return Constructors_UsingDists_cdf({ env: this.env }, this.t, n); + } + + inv(n: number): resultFloat { + return Constructors_UsingDists_inv({ env: this.env }, this.t, n); + } + + normalize(): resultDist { + return Constructors_UsingDists_normalize({ env: this.env }, this.t); + } + + toPointSet(): resultDist { + return Constructors_UsingDists_toPointSet({ env: this.env }, this.t); + } + + toSampleSet(n: number): resultDist { + return Constructors_UsingDists_toSampleSet({ env: this.env }, this.t, n); + } + + truncate(left: number, right: number): resultDist { + return Constructors_UsingDists_truncate( { env: this.env }, - { tag: "FromDist", value: [{ tag: "ToFloat", value: "Mean" }, this.t] } + this.t, + left, + right ); } - pdf(n: number): outputType { - return runR( + inspect(): resultDist { + return Constructors_UsingDists_inspect({ env: this.env }, this.t); + } + + toString(): resultString { + return Constructors_UsingDists_toString({ env: this.env }, this.t); + } + + toSparkline(n: number): resultString { + return Constructors_UsingDists_toSparkline({ env: this.env }, this.t, n); + } + + algebraicAdd(d2: GenericDist): resultDist { + return Constructors_UsingDists_algebraicAdd( { env: this.env }, - { - tag: "FromDist", - value: [{ tag: "ToFloat", value: { NAME: "Pdf", VAL: n } }, this.t], - } + this.t, + d2.t ); } - cdf(n: number): outputType { - return runR( + algebraicMultiply(d2: GenericDist): resultDist { + return Constructors_UsingDists_algebraicMultiply( { env: this.env }, - { - tag: "FromDist", - value: [{ tag: "ToFloat", value: { NAME: "Pdf", VAL: n } }, this.t], - } + this.t, + d2.t ); } - inv(n: number): outputType { - return runR( + algebraicDivide(d2: GenericDist): resultDist { + return Constructors_UsingDists_algebraicDivide( { env: this.env }, - { - tag: "FromDist", - value: [{ tag: "ToFloat", value: { NAME: "Pdf", VAL: n } }, this.t], - } + this.t, + d2.t ); } - normalize(n: number): outputType { - return runR( + algebraicSubtract(d2: GenericDist): resultDist { + return Constructors_UsingDists_algebraicSubtract( { env: this.env }, - { - tag: "FromDist", - value: [{ tag: "ToDist", value: "Normalize" }, this.t], - } + this.t, + d2.t ); } - toPointSet(): outputType { - return runR( + algebraicLogarithm(d2: GenericDist): resultDist { + return Constructors_UsingDists_algebraicLogarithm( { env: this.env }, - { - tag: "FromDist", - value: [{ tag: "ToDist", value: "ToPointSet" }, this.t], - } + this.t, + d2.t ); } - inspect(): outputType { - return runR( + algebraicExponentiate(d2: GenericDist): resultDist { + return Constructors_UsingDists_algebraicExponentiate( { env: this.env }, - { tag: "FromDist", value: [{ tag: "ToDist", value: "Inspect" }, this.t] } + this.t, + d2.t ); } - toSampleSet(n: number): outputType { - return runR( + pointwiseAdd(d2: GenericDist): resultDist { + return Constructors_UsingDists_pointwiseAdd( { env: this.env }, - { - tag: "FromDist", - value: [ - { tag: "ToDist", value: { tag: "ToSampleSet", value: n } }, - this.t, - ], - } + this.t, + d2.t ); } - truncate( - left: null | undefined | number, - right: null | undefined | number - ): outputType { - return runR( + pointwiseMultiply(d2: GenericDist): resultDist { + return Constructors_UsingDists_pointwiseMultiply( { env: this.env }, - { - tag: "FromDist", - value: [ - { tag: "ToDist", value: { tag: "Truncate", value: [left, right] } }, - this.t, - ], - } + this.t, + d2.t ); } - toString(): outputType { - return runR( + pointwiseDivide(d2: GenericDist): resultDist { + return Constructors_UsingDists_pointwiseDivide( { env: this.env }, - { - tag: "FromDist", - value: [{ tag: "ToString", value: "ToString" }, this.t], - } + this.t, + d2.t ); } - toSparkline(n: number): outputType { - return runR( + pointwiseSubtract(d2: GenericDist): resultDist { + return Constructors_UsingDists_pointwiseSubtract( { env: this.env }, - { - tag: "FromDist", - value: [ - { tag: "ToString", value: { tag: "ToSparkline", value: n } }, - this.t, - ], - } + this.t, + d2.t ); } - add(g2: genericDist): outputType { - return runR( + pointwiseLogarithm(d2: GenericDist): resultDist { + return Constructors_UsingDists_pointwiseLogarithm( { env: this.env }, - { - tag: "FromDist", - value: [ - { - tag: "ToDistCombination", - value: [ - { - tag: "ToDistCombination", - value: ["Algebraic", "Add", { NAME: "Dist", VAL: g2 }], - }, - ], - }, - this.t, - ], - } + this.t, + d2.t + ); + } + + pointwiseExponentiate(d2: GenericDist): resultDist { + return Constructors_UsingDists_pointwiseExponentiate( + { env: this.env }, + this.t, + d2.t ); } } diff --git a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res index 1d25f64c..2014880f 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res +++ b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res @@ -190,10 +190,7 @@ module Constructors = { module UsingDists = { module C = GenericDist_Types.Constructors.UsingDists open OutputLocal - type dist = GenericDist_Types.genericDist - type fResult = result - type dResult = result - type sResult = result + type floatResult= result let mean = (~env, dist) => run(~env, C.mean(dist))->toFloatR let sample = (~env, dist) => run(~env, C.sample(dist))->toFloatR @@ -231,4 +228,4 @@ module Constructors = { let pointwiseExponentiate = (~env, dist1, dist2) => run(~env, C.pointwiseSubtract(dist1, dist2))->toDistR } -} +} \ No newline at end of file diff --git a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.resi b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.resi index e39d5848..b0799dc9 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.resi +++ b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.resi @@ -4,19 +4,21 @@ type env = { xyPointLength: int, } +open GenericDist_Types + @genType type outputType = - | Dist(GenericDist_Types.genericDist) + | Dist(genericDist) | Float(float) | String(string) - | GenDistError(GenericDist_Types.error) + | GenDistError(error) @genType let run: (~env: env, GenericDist_Types.Operation.genericFunctionCallInfo) => outputType let runFromDist: ( ~env: env, ~functionCallInfo: GenericDist_Types.Operation.fromDist, - GenericDist_Types.genericDist, + genericDist, ) => outputType let runFromFloat: ( ~env: env, @@ -26,45 +28,70 @@ let runFromFloat: ( module Output: { type t = outputType - let toDist: t => option - let toDistR: t => result + let toDist: t => option + let toDistR: t => result let toFloat: t => option - let toFloatR: t => result + let toFloatR: t => result let toString: t => option - let toStringR: t => result - let toError: t => option + let toStringR: t => result + let toError: t => option let fmap: (~env: env, t, GenericDist_Types.Operation.singleParamaterFunction) => t } module Constructors: { module UsingDists: { - type dist = GenericDist_Types.genericDist - type fResult = result - type dResult = result - type sResult = result - let mean: (~env: env, dist) => fResult - let sample: (~env: env, dist) => fResult - let cdf: (~env: env, dist, float) => fResult - let inv: (~env: env, dist, float) => fResult - let pdf: (~env: env, dist, float) => fResult - let normalize: (~env: env, dist) => dResult - let toPointSet: (~env: env, dist) => dResult - let toSampleSet: (~env: env, dist, int) => dResult - let truncate: (~env: env, dist, option, option) => dResult - let inspect: (~env: env, dist) => dResult - let toString: (~env: env, dist) => sResult - let toSparkline: (~env: env, dist, int) => sResult - let algebraicAdd: (~env: env, dist, dist) => dResult - let algebraicMultiply: (~env: env, dist, dist) => dResult - let algebraicDivide: (~env: env, dist, dist) => dResult - let algebraicSubtract: (~env: env, dist, dist) => dResult - let algebraicLogarithm: (~env: env, dist, dist) => dResult - let algebraicExponentiate: (~env: env, dist, dist) => dResult - let pointwiseAdd: (~env: env, dist, dist) => dResult - let pointwiseMultiply: (~env: env, dist, dist) => dResult - let pointwiseDivide: (~env: env, dist, dist) => dResult - let pointwiseSubtract: (~env: env, dist, dist) => dResult - let pointwiseLogarithm: (~env: env, dist, dist) => dResult - let pointwiseExponentiate: (~env: env, dist, dist) => dResult + @genType + let mean: (~env: env, genericDist) => result + @genType + let sample: (~env: env, genericDist) => result + @genType + let cdf: (~env: env, genericDist, float) => result + @genType + let inv: (~env: env, genericDist, float) => result + @genType + let pdf: (~env: env, genericDist, float) => result + @genType + let normalize: (~env: env, genericDist) => result + @genType + let toPointSet: (~env: env, genericDist) => result + @genType + let toSampleSet: (~env: env, genericDist, int) => result + @genType + let truncate: ( + ~env: env, + genericDist, + option, + option, + ) => result + @genType + let inspect: (~env: env, genericDist) => result + @genType + let toString: (~env: env, genericDist) => result + @genType + let toSparkline: (~env: env, genericDist, int) => result + @genType + let algebraicAdd: (~env: env, genericDist, genericDist) => result + @genType + let algebraicMultiply: (~env: env, genericDist, genericDist) => result + @genType + let algebraicDivide: (~env: env, genericDist, genericDist) => result + @genType + let algebraicSubtract: (~env: env, genericDist, genericDist) => result + @genType + let algebraicLogarithm: (~env: env, genericDist, genericDist) => result + @genType + let algebraicExponentiate: (~env: env, genericDist, genericDist) => result + @genType + let pointwiseAdd: (~env: env, genericDist, genericDist) => result + @genType + let pointwiseMultiply: (~env: env, genericDist, genericDist) => result + @genType + let pointwiseDivide: (~env: env, genericDist, genericDist) => result + @genType + let pointwiseSubtract: (~env: env, genericDist, genericDist) => result + @genType + let pointwiseLogarithm: (~env: env, genericDist, genericDist) => result + @genType + let pointwiseExponentiate: (~env: env, genericDist, genericDist) => result } } diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res index f472a6e0..90189d00 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res @@ -114,7 +114,7 @@ module Constructors = { let inspect = (dist): t => FromDist(ToDist(Inspect), 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( + let algebraicAdd = (dist1, dist2: genericDist): t => FromDist( ToDistCombination(Algebraic, #Add, #Dist(dist2)), dist1, ) @@ -164,3 +164,63 @@ module Constructors = { ) } } + +module DistVariant = { + type t = + | Mean(genericDist) + | Sample(genericDist) + | Cdf(genericDist, float) + | Inv(genericDist, float) + | Pdf(genericDist, float) + | Normalize(genericDist) + | ToPointSet(genericDist) + | ToSampleSet(genericDist, int) + | Truncate(genericDist, option, option) + | Inspect(genericDist) + | ToString(genericDist) + | ToSparkline(genericDist, int) + | AlgebraicAdd(genericDist, genericDist) + | AlgebraicMultiply(genericDist, genericDist) + | AlgebraicDivide(genericDist, genericDist) + | AlgebraicSubtract(genericDist, genericDist) + | AlgebraicLogarithm(genericDist, genericDist) + | AlgebraicExponentiate(genericDist, genericDist) + | PointwiseAdd(genericDist, genericDist) + | PointwiseMultiply(genericDist, genericDist) + | PointwiseDivide(genericDist, genericDist) + | PointwiseSubtract(genericDist, genericDist) + | PointwiseLogarithm(genericDist, genericDist) + | PointwiseExponentiate(genericDist, genericDist) + + let toGenericFunctionCallInfo = (t: t) => + switch t { + | Mean(d) => Operation.FromDist(ToFloat(#Mean), d) + | Sample(d) => FromDist(ToFloat(#Mean), d) + | Cdf(d, f) => FromDist(ToFloat(#Cdf(f)), d) + | Inv(d, f) => FromDist(ToFloat(#Inv(f)), d) + | Pdf(d, f) => FromDist(ToFloat(#Pdf(f)), d) + | Normalize(d) => FromDist(ToDist(Normalize), d) + | ToPointSet(d) => FromDist(ToDist(ToPointSet), d) + | ToSampleSet(d, r) => FromDist(ToDist(ToSampleSet(r)), d) + | Truncate(d, left, right) => FromDist(ToDist(Truncate(left, right)), d) + | Inspect(d) => FromDist(ToDist(Inspect), d) + | ToString(d) => FromDist(ToString(ToString), d) + | ToSparkline(d, n) => FromDist(ToString(ToSparkline(n)), d) + | AlgebraicAdd(d1, d2) => FromDist(ToDistCombination(Algebraic, #Add, #Dist(d2)), d1) + | AlgebraicMultiply(d1, d2) => FromDist(ToDistCombination(Algebraic, #Multiply, #Dist(d2)), d1) + | AlgebraicDivide(d1, d2) => FromDist(ToDistCombination(Algebraic, #Divide, #Dist(d2)), d1) + | AlgebraicSubtract(d1, d2) => FromDist(ToDistCombination(Algebraic, #Subtract, #Dist(d2)), d1) + | AlgebraicLogarithm(d1, d2) => + FromDist(ToDistCombination(Algebraic, #Logarithm, #Dist(d2)), d1) + | AlgebraicExponentiate(d1, d2) => + FromDist(ToDistCombination(Algebraic, #Exponentiate, #Dist(d2)), d1) + | PointwiseAdd(d1, d2) => FromDist(ToDistCombination(Pointwise, #Add, #Dist(d2)), d1) + | PointwiseMultiply(d1, d2) => FromDist(ToDistCombination(Pointwise, #Multiply, #Dist(d2)), d1) + | PointwiseDivide(d1, d2) => FromDist(ToDistCombination(Pointwise, #Divide, #Dist(d2)), d1) + | PointwiseSubtract(d1, d2) => FromDist(ToDistCombination(Pointwise, #Subtract, #Dist(d2)), d1) + | PointwiseLogarithm(d1, d2) => + FromDist(ToDistCombination(Pointwise, #Logarithm, #Dist(d2)), d1) + | PointwiseExponentiate(d1, d2) => + FromDist(ToDistCombination(Pointwise, #Exponentiate, #Dist(d2)), d1) + } +} \ No newline at end of file diff --git a/packages/squiggle-lang/src/rescript/TSInterface.res b/packages/squiggle-lang/src/rescript/TSInterface.res index 8df300f8..26b694a5 100644 --- a/packages/squiggle-lang/src/rescript/TSInterface.res +++ b/packages/squiggle-lang/src/rescript/TSInterface.res @@ -11,4 +11,11 @@ type genericDist = GenericDist_Types.genericDist; type error = GenericDist_Types.error; @genType -let runDistributionOperation = DistributionOperation.run; \ No newline at end of file +let runDistributionOperation = DistributionOperation.run; + +@genType +type resultDist = result +@genType +type resultFloat = result +@genType +type resultString = result \ No newline at end of file From 4c99a50d895328f87a7742ff0a461465ed0f154a Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Fri, 8 Apr 2022 15:57:18 -0400 Subject: [PATCH 27/41] Fix from CR --- .../rescript/Distributions/GenericDist/GenericDist_Types.res | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res index 90189d00..45ad6f64 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res @@ -103,7 +103,7 @@ module Constructors = { module UsingDists = { let mean = (dist): t => FromDist(ToFloat(#Mean), dist) - let sample = (dist): t => FromDist(ToFloat(#Mean), dist) + let sample = (dist): t => FromDist(ToFloat(#Sample), dist) let cdf = (dist, f): t => FromDist(ToFloat(#Cdf(f)), dist) let inv = (dist, f): t => FromDist(ToFloat(#Inv(f)), dist) let pdf = (dist, f): t => FromDist(ToFloat(#Pdf(f)), dist) From d62ccc27bd9afd82573ff0d291ab52e301d72c47 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Fri, 8 Apr 2022 16:09:00 -0400 Subject: [PATCH 28/41] Minor refactor of DistributionOperation Constructors --- .../DistributionOperation.res | 52 +++++++++---------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res index 2014880f..7d58af7b 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res +++ b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res @@ -190,42 +190,40 @@ module Constructors = { module UsingDists = { module C = GenericDist_Types.Constructors.UsingDists open OutputLocal - type floatResult= result - - let mean = (~env, dist) => run(~env, C.mean(dist))->toFloatR - let sample = (~env, dist) => run(~env, C.sample(dist))->toFloatR - let cdf = (~env, dist, f) => run(~env, C.cdf(dist, f))->toFloatR - let inv = (~env, dist, f) => run(~env, C.inv(dist, f))->toFloatR - let pdf = (~env, dist, f) => run(~env, C.pdf(dist, f))->toFloatR - let normalize = (~env, dist) => run(~env, C.normalize(dist))->toDistR - let toPointSet = (~env, dist) => run(~env, C.toPointSet(dist))->toDistR - let toSampleSet = (~env, dist, n) => run(~env, C.toSampleSet(dist, n))->toDistR + let mean = (~env, dist) => C.mean(dist)->run(~env)->toFloatR + let sample = (~env, dist) => C.sample(dist)->run(~env)->toFloatR + let cdf = (~env, dist, f) => C.cdf(dist, f)->run(~env)->toFloatR + let inv = (~env, dist, f) => C.inv(dist, f)->run(~env)->toFloatR + let pdf = (~env, dist, f) => C.pdf(dist, f)->run(~env)->toFloatR + let normalize = (~env, dist) => C.normalize(dist)->run(~env)->toDistR + let toPointSet = (~env, dist) => C.toPointSet(dist)->run(~env)->toDistR + let toSampleSet = (~env, dist, n) => C.toSampleSet(dist, n)->run(~env)->toDistR let truncate = (~env, dist, leftCutoff, rightCutoff) => - run(~env, C.truncate(dist, leftCutoff, rightCutoff))->toDistR - let inspect = (~env, dist) => run(~env, C.inspect(dist))->toDistR - let toString = (~env, dist) => run(~env, C.toString(dist))->toStringR - let toSparkline = (~env, dist, buckets) => run(~env, C.toSparkline(dist, buckets))->toStringR - let algebraicAdd = (~env, dist1, dist2) => run(~env, C.algebraicAdd(dist1, dist2))->toDistR + C.truncate(dist, leftCutoff, rightCutoff)->run(~env)->toDistR + let inspect = (~env, dist) => C.inspect(dist)->run(~env)->toDistR + let toString = (~env, dist) => C.toString(dist)->run(~env)->toStringR + let toSparkline = (~env, dist, buckets) => C.toSparkline(dist, buckets)->run(~env)->toStringR + let algebraicAdd = (~env, dist1, dist2) => C.algebraicAdd(dist1, dist2)->run(~env)->toDistR let algebraicMultiply = (~env, dist1, dist2) => - run(~env, C.algebraicMultiply(dist1, dist2))->toDistR + C.algebraicMultiply(dist1, dist2)->run(~env)->toDistR let algebraicDivide = (~env, dist1, dist2) => - run(~env, C.algebraicDivide(dist1, dist2))->toDistR + C.algebraicDivide(dist1, dist2)->run(~env)->toDistR let algebraicSubtract = (~env, dist1, dist2) => - run(~env, C.algebraicSubtract(dist1, dist2))->toDistR + C.algebraicSubtract(dist1, dist2)->run(~env)->toDistR let algebraicLogarithm = (~env, dist1, dist2) => - run(~env, C.algebraicLogarithm(dist1, dist2))->toDistR + C.algebraicLogarithm(dist1, dist2)->run(~env)->toDistR let algebraicExponentiate = (~env, dist1, dist2) => - run(~env, C.algebraicExponentiate(dist1, dist2))->toDistR - let pointwiseAdd = (~env, dist1, dist2) => run(~env, C.pointwiseAdd(dist1, dist2))->toDistR + C.algebraicExponentiate(dist1, dist2)->run(~env)->toDistR + let pointwiseAdd = (~env, dist1, dist2) => C.pointwiseAdd(dist1, dist2)->run(~env)->toDistR let pointwiseMultiply = (~env, dist1, dist2) => - run(~env, C.pointwiseMultiply(dist1, dist2))->toDistR + C.pointwiseMultiply(dist1, dist2)->run(~env)->toDistR let pointwiseDivide = (~env, dist1, dist2) => - run(~env, C.pointwiseDivide(dist1, dist2))->toDistR + C.pointwiseDivide(dist1, dist2)->run(~env)->toDistR let pointwiseSubtract = (~env, dist1, dist2) => - run(~env, C.pointwiseSubtract(dist1, dist2))->toDistR + C.pointwiseSubtract(dist1, dist2)->run(~env)->toDistR let pointwiseLogarithm = (~env, dist1, dist2) => - run(~env, C.pointwiseSubtract(dist1, dist2))->toDistR + C.pointwiseSubtract(dist1, dist2)->run(~env)->toDistR let pointwiseExponentiate = (~env, dist1, dist2) => - run(~env, C.pointwiseSubtract(dist1, dist2))->toDistR + C.pointwiseSubtract(dist1, dist2)->run(~env)->toDistR } -} \ No newline at end of file +} From 0af0c9e274cd8ab49e32850b4f4f0a7c9373cc55 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Fri, 8 Apr 2022 19:48:53 -0400 Subject: [PATCH 29/41] Added tests for index.js and fixed some corresponding functionality --- packages/squiggle-lang/__tests__/JS__Test.ts | 82 ++++-- packages/squiggle-lang/src/js/index.ts | 239 +++++++++--------- .../DistributionOperation.res | 4 +- .../DistributionOperation.resi | 2 - .../Distributions/GenericDist/GenericDist.res | 4 +- .../GenericDist/GenericDist_Types.res | 1 + .../Distributions/PointSetDist/Continuous.res | 3 + .../PointSetDist/PointSetDist.res | 3 +- 8 files changed, 191 insertions(+), 147 deletions(-) diff --git a/packages/squiggle-lang/__tests__/JS__Test.ts b/packages/squiggle-lang/__tests__/JS__Test.ts index aded69c1..07a4cabe 100644 --- a/packages/squiggle-lang/__tests__/JS__Test.ts +++ b/packages/squiggle-lang/__tests__/JS__Test.ts @@ -1,34 +1,66 @@ -import { run } from '../src/js/index'; +import { run, GenericDist, resultMap } from "../src/js/index"; let testRun = (x: string) => { - let result = run(x) - if(result.tag == 'Ok'){ - return { tag: 'Ok', value: result.value.exports } + let result = run(x); + if (result.tag == "Ok") { + return { tag: "Ok", value: result.value.exports }; + } else { + return result; } - else { - return result - } -} +}; describe("Simple calculations and results", () => { - test("mean(normal(5,2))", () => { - expect(testRun("mean(normal(5,2))")).toEqual({ tag: 'Ok', value: [ { NAME: 'Float', VAL: 5 } ] }) - }) - test("10+10", () => { - let foo = testRun("10 + 10") - expect(foo).toEqual({ tag: 'Ok', value: [ { NAME: 'Float', VAL: 20 } ] }) - }) -}) + test("mean(normal(5,2))", () => { + expect(testRun("mean(normal(5,2))")).toEqual({ + tag: "Ok", + value: [{ NAME: "Float", VAL: 5 }], + }); + }); + test("10+10", () => { + let foo = testRun("10 + 10"); + expect(foo).toEqual({ tag: "Ok", value: [{ NAME: "Float", VAL: 20 }] }); + }); +}); describe("Log function", () => { - test("log(1) = 0", () => { - let foo = testRun("log(1)") - expect(foo).toEqual({ tag: 'Ok', value: [ { NAME: 'Float', VAL: 0} ]}) - }) -}) + test("log(1) = 0", () => { + let foo = testRun("log(1)"); + expect(foo).toEqual({ tag: "Ok", value: [{ NAME: "Float", VAL: 0 }] }); + }); +}); describe("Multimodal too many weights error", () => { - test("mm(0,0,[0,0,0])", () => { - let foo = testRun("mm(0,0,[0,0,0])") - expect(foo).toEqual({ "tag": "Error", "value": "Function multimodal error: Too many weights provided" }) - }) + test("mm(0,0,[0,0,0])", () => { + let foo = testRun("mm(0,0,[0,0,0])"); + expect(foo).toEqual({ + tag: "Error", + value: "Function multimodal error: Too many weights provided", + }); + }); +}); + +describe("GenericDist", () => { + let dist = new GenericDist( + { tag: "SampleSet", value: [3, 4, 5, 6, 6, 7, 10, 15, 30] }, + { sampleCount: 100, xyPointLength: 100 } + ); + test("mean", () => { + expect(dist.mean().value).toBeCloseTo(3.737); + }); + test("pdf", () => { + expect(dist.pdf(5.0).value).toBeCloseTo(0.0431); + }); + test("cdf", () => { + expect(dist.cdf(5.0).value).toBeCloseTo(0.155); + }); + test("inv", () => { + expect(dist.inv(0.5).value).toBeCloseTo(9.458); + }); + test("toPointSet", () => { + expect( + resultMap(dist.toPointSet(), (r: GenericDist) => r.toString()).value.value + ).toBe("Point Set Distribution"); + }); + test("toSparkline", () => { + expect(dist.toSparkline(20).value).toBe("▁▁▃▅███▆▄▃▂▁▁▂▂▃▂▁▁▁"); + }); }); diff --git a/packages/squiggle-lang/src/js/index.ts b/packages/squiggle-lang/src/js/index.ts index a250c4fc..b690d581 100644 --- a/packages/squiggle-lang/src/js/index.ts +++ b/packages/squiggle-lang/src/js/index.ts @@ -7,7 +7,6 @@ import type { } from "../rescript/ProgramEvaluator.gen"; export type { SamplingInputs, exportEnv, exportDistribution }; export type { t as DistPlus } from "../rescript/OldInterpreter/DistPlus.gen"; -import type { Operation_genericFunctionCallInfo } from "../rescript/Distributions/GenericDist/GenericDist_Types.gen"; import { genericDist, resultDist, @@ -16,30 +15,30 @@ import { } from "../rescript/TSInterface.gen"; import { env, - Constructors_UsingDists_mean, - Constructors_UsingDists_sample, - Constructors_UsingDists_pdf, - Constructors_UsingDists_cdf, - Constructors_UsingDists_inv, - Constructors_UsingDists_normalize, - Constructors_UsingDists_toPointSet, - Constructors_UsingDists_toSampleSet, - Constructors_UsingDists_truncate, - Constructors_UsingDists_inspect, - Constructors_UsingDists_toString, - Constructors_UsingDists_toSparkline, - Constructors_UsingDists_algebraicAdd, - Constructors_UsingDists_algebraicMultiply, - Constructors_UsingDists_algebraicDivide, - Constructors_UsingDists_algebraicSubtract, - Constructors_UsingDists_algebraicLogarithm, - Constructors_UsingDists_algebraicExponentiate, - Constructors_UsingDists_pointwiseAdd, - Constructors_UsingDists_pointwiseMultiply, - Constructors_UsingDists_pointwiseDivide, - Constructors_UsingDists_pointwiseSubtract, - Constructors_UsingDists_pointwiseLogarithm, - Constructors_UsingDists_pointwiseExponentiate, + Constructors_mean, + Constructors_sample, + Constructors_pdf, + Constructors_cdf, + Constructors_inv, + Constructors_normalize, + Constructors_toPointSet, + Constructors_toSampleSet, + Constructors_truncate, + Constructors_inspect, + Constructors_toString, + Constructors_toSparkline, + Constructors_algebraicAdd, + Constructors_algebraicMultiply, + Constructors_algebraicDivide, + Constructors_algebraicSubtract, + Constructors_algebraicLogarithm, + Constructors_algebraicExponentiate, + Constructors_pointwiseAdd, + Constructors_pointwiseMultiply, + Constructors_pointwiseDivide, + Constructors_pointwiseSubtract, + Constructors_pointwiseLogarithm, + Constructors_pointwiseExponentiate, } from "../rescript/Distributions/DistributionOperation/DistributionOperation.gen"; export let defaultSamplingInputs: SamplingInputs = { @@ -60,160 +59,172 @@ export function run( return runAll(squiggleString, si, env); } -class GenericDist { +export function resultMap( + r: + | { + tag: "Ok"; + value: any; + } + | { + tag: "Error"; + value: any; + }, + mapFn: any +): + | { + tag: "Ok"; + value: any; + } + | { + tag: "Error"; + value: any; + } { + if (r.tag === "Ok") { + return { tag: "Ok", value: mapFn(r.value) }; + } else { + return r; + } +} + +export class GenericDist { t: genericDist; env: env; constructor(t: genericDist, env: env) { this.t = t; + this.env = env; + return this; } - mean(): resultFloat { - return Constructors_UsingDists_mean({ env: this.env }, this.t); + mapResultDist(r: resultDist) { + return resultMap(r, (v: genericDist) => new GenericDist(v, this.env)); + } + + mean() { + return Constructors_mean({ env: this.env }, this.t); } sample(): resultFloat { - return Constructors_UsingDists_sample({ env: this.env }, this.t); + return Constructors_sample({ env: this.env }, this.t); } pdf(n: number): resultFloat { - return Constructors_UsingDists_pdf({ env: this.env }, this.t, n); + return Constructors_pdf({ env: this.env }, this.t, n); } cdf(n: number): resultFloat { - return Constructors_UsingDists_cdf({ env: this.env }, this.t, n); + return Constructors_cdf({ env: this.env }, this.t, n); } inv(n: number): resultFloat { - return Constructors_UsingDists_inv({ env: this.env }, this.t, n); + return Constructors_inv({ env: this.env }, this.t, n); } - normalize(): resultDist { - return Constructors_UsingDists_normalize({ env: this.env }, this.t); - } - - toPointSet(): resultDist { - return Constructors_UsingDists_toPointSet({ env: this.env }, this.t); - } - - toSampleSet(n: number): resultDist { - return Constructors_UsingDists_toSampleSet({ env: this.env }, this.t, n); - } - - truncate(left: number, right: number): resultDist { - return Constructors_UsingDists_truncate( - { env: this.env }, - this.t, - left, - right + normalize() { + return this.mapResultDist( + Constructors_normalize({ env: this.env }, this.t) ); } - inspect(): resultDist { - return Constructors_UsingDists_inspect({ env: this.env }, this.t); + toPointSet() { + return this.mapResultDist( + Constructors_toPointSet({ env: this.env }, this.t) + ); + } + + toSampleSet(n: number) { + return this.mapResultDist( + Constructors_toSampleSet({ env: this.env }, this.t, n) + ); + } + + truncate(left: number, right: number) { + return this.mapResultDist( + Constructors_truncate({ env: this.env }, this.t, left, right) + ); + } + + inspect() { + return this.mapResultDist(Constructors_inspect({ env: this.env }, this.t)); } toString(): resultString { - return Constructors_UsingDists_toString({ env: this.env }, this.t); + return Constructors_toString({ env: this.env }, this.t); } toSparkline(n: number): resultString { - return Constructors_UsingDists_toSparkline({ env: this.env }, this.t, n); + return Constructors_toSparkline({ env: this.env }, this.t, n); } - algebraicAdd(d2: GenericDist): resultDist { - return Constructors_UsingDists_algebraicAdd( - { env: this.env }, - this.t, - d2.t + algebraicAdd(d2: GenericDist) { + return this.mapResultDist( + Constructors_algebraicAdd({ env: this.env }, this.t, d2.t) ); } - algebraicMultiply(d2: GenericDist): resultDist { - return Constructors_UsingDists_algebraicMultiply( - { env: this.env }, - this.t, - d2.t + algebraicMultiply(d2: GenericDist) { + return this.mapResultDist( + Constructors_algebraicMultiply({ env: this.env }, this.t, d2.t) ); } - algebraicDivide(d2: GenericDist): resultDist { - return Constructors_UsingDists_algebraicDivide( - { env: this.env }, - this.t, - d2.t + algebraicDivide(d2: GenericDist) { + return this.mapResultDist( + Constructors_algebraicDivide({ env: this.env }, this.t, d2.t) ); } - algebraicSubtract(d2: GenericDist): resultDist { - return Constructors_UsingDists_algebraicSubtract( - { env: this.env }, - this.t, - d2.t + algebraicSubtract(d2: GenericDist) { + return this.mapResultDist( + Constructors_algebraicSubtract({ env: this.env }, this.t, d2.t) ); } - algebraicLogarithm(d2: GenericDist): resultDist { - return Constructors_UsingDists_algebraicLogarithm( - { env: this.env }, - this.t, - d2.t + algebraicLogarithm(d2: GenericDist) { + return this.mapResultDist( + Constructors_algebraicLogarithm({ env: this.env }, this.t, d2.t) ); } - algebraicExponentiate(d2: GenericDist): resultDist { - return Constructors_UsingDists_algebraicExponentiate( - { env: this.env }, - this.t, - d2.t + algebraicExponentiate(d2: GenericDist) { + return this.mapResultDist( + Constructors_algebraicExponentiate({ env: this.env }, this.t, d2.t) ); } - pointwiseAdd(d2: GenericDist): resultDist { - return Constructors_UsingDists_pointwiseAdd( - { env: this.env }, - this.t, - d2.t + pointwiseAdd(d2: GenericDist) { + return this.mapResultDist( + Constructors_pointwiseAdd({ env: this.env }, this.t, d2.t) ); } - pointwiseMultiply(d2: GenericDist): resultDist { - return Constructors_UsingDists_pointwiseMultiply( - { env: this.env }, - this.t, - d2.t + pointwiseMultiply(d2: GenericDist) { + return this.mapResultDist( + Constructors_pointwiseMultiply({ env: this.env }, this.t, d2.t) ); } - pointwiseDivide(d2: GenericDist): resultDist { - return Constructors_UsingDists_pointwiseDivide( - { env: this.env }, - this.t, - d2.t + pointwiseDivide(d2: GenericDist) { + return this.mapResultDist( + Constructors_pointwiseDivide({ env: this.env }, this.t, d2.t) ); } - pointwiseSubtract(d2: GenericDist): resultDist { - return Constructors_UsingDists_pointwiseSubtract( - { env: this.env }, - this.t, - d2.t + pointwiseSubtract(d2: GenericDist) { + return this.mapResultDist( + Constructors_pointwiseSubtract({ env: this.env }, this.t, d2.t) ); } - pointwiseLogarithm(d2: GenericDist): resultDist { - return Constructors_UsingDists_pointwiseLogarithm( - { env: this.env }, - this.t, - d2.t + pointwiseLogarithm(d2: GenericDist) { + return this.mapResultDist( + Constructors_pointwiseLogarithm({ env: this.env }, this.t, d2.t) ); } - pointwiseExponentiate(d2: GenericDist): resultDist { - return Constructors_UsingDists_pointwiseExponentiate( - { env: this.env }, - this.t, - d2.t + pointwiseExponentiate(d2: GenericDist) { + return this.mapResultDist( + Constructors_pointwiseExponentiate({ env: this.env }, this.t, d2.t) ); } } diff --git a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res index 7d58af7b..12b94bcc 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res +++ b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res @@ -187,8 +187,7 @@ module Output = { } module Constructors = { - module UsingDists = { - module C = GenericDist_Types.Constructors.UsingDists + module C = GenericDist_Types.Constructors.UsingDists; open OutputLocal let mean = (~env, dist) => C.mean(dist)->run(~env)->toFloatR let sample = (~env, dist) => C.sample(dist)->run(~env)->toFloatR @@ -225,5 +224,4 @@ module Constructors = { C.pointwiseSubtract(dist1, dist2)->run(~env)->toDistR let pointwiseExponentiate = (~env, dist1, dist2) => C.pointwiseSubtract(dist1, dist2)->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 b0799dc9..ce0fca72 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.resi +++ b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.resi @@ -39,7 +39,6 @@ module Output: { } module Constructors: { - module UsingDists: { @genType let mean: (~env: env, genericDist) => result @genType @@ -93,5 +92,4 @@ module Constructors: { let pointwiseLogarithm: (~env: env, genericDist, genericDist) => result @genType let pointwiseExponentiate: (~env: env, genericDist, genericDist) => result - } } diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res index 58366a77..4815e98c 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res @@ -83,8 +83,8 @@ let toPointSet = ( let toSparkline = (t: t, ~sampleCount: int, ~buckets: int=20, unit): result => t - ->toPointSet(~xSelection=#Linear, ~xyPointLength=buckets, ~sampleCount, ()) - ->E.R.bind(r => r->PointSetDist.toSparkline->E.R2.errMap(r => Error(GenericDist_Types.Other(r)))) + ->toPointSet(~xSelection=#Linear, ~xyPointLength=buckets*3, ~sampleCount, ()) + ->E.R.bind(r => r->PointSetDist.toSparkline(buckets)->E.R2.errMap(r => Error(GenericDist_Types.Other(r)))) module Truncate = { let trySymbolicSimplification = (leftCutoff, rightCutoff, t: t): option => diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res index 45ad6f64..1bfb3e82 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res @@ -102,6 +102,7 @@ module Constructors = { type t = Operation.genericFunctionCallInfo module UsingDists = { + @genType let mean = (dist): t => FromDist(ToFloat(#Mean), dist) let sample = (dist): t => FromDist(ToFloat(#Sample), dist) let cdf = (dist, f): t => FromDist(ToFloat(#Cdf(f)), dist) diff --git a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Continuous.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Continuous.res index f01457b7..aa27fb62 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Continuous.res +++ b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Continuous.res @@ -249,6 +249,9 @@ module T = Dist({ ) }) +let downsampleEquallyOverX = (length, t): t => + t |> shapeMap(XYShape.XsConversion.proportionEquallyOverX(length)) + /* This simply creates multiple copies of the continuous distribution, scaled and shifted according to each discrete data point, and then adds them all together. */ let combineAlgebraicallyWithDiscrete = ( diff --git a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res index 8224f4cb..c7bec8a9 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res @@ -203,7 +203,8 @@ let operate = (distToFloatOp: Operation.distToFloatOperation, s): float => | #Mean => T.mean(s) } -let toSparkline = (t: t) => +let toSparkline = (t: t, n) => T.toContinuous(t) + ->E.O2.fmap(Continuous.downsampleEquallyOverX(n)) ->E.O2.toResult("toContinous Error: Could not convert into continuous distribution") ->E.R2.fmap(r => Continuous.getShape(r).ys->Sparklines.create()) \ No newline at end of file From 2dc57bedc57a5b4545787b1e88a46c5cce51854b Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Fri, 8 Apr 2022 21:31:08 -0400 Subject: [PATCH 30/41] Added more tests to JS__Test.ts, and added SampleN functionality to SampleSetDist --- packages/squiggle-lang/__tests__/JS__Test.ts | 22 ++++++++++++++++++- .../DistributionOperation.res | 4 ++-- .../Distributions/GenericDist/GenericDist.res | 8 ++++--- .../GenericDist/GenericDist_Types.res | 2 +- .../Distributions/SampleSetDist/SampleSet.res | 14 ++++++++++++ .../squiggle-lang/src/rescript/Utility/E.res | 2 ++ 6 files changed, 45 insertions(+), 7 deletions(-) diff --git a/packages/squiggle-lang/__tests__/JS__Test.ts b/packages/squiggle-lang/__tests__/JS__Test.ts index 07a4cabe..ba2f91f4 100644 --- a/packages/squiggle-lang/__tests__/JS__Test.ts +++ b/packages/squiggle-lang/__tests__/JS__Test.ts @@ -39,10 +39,18 @@ describe("Multimodal too many weights error", () => { }); describe("GenericDist", () => { + + //It's important that sampleCount is less than 9. If it's more, than that will create randomness + let env = { sampleCount: 8, xyPointLength: 100 }; let dist = new GenericDist( { tag: "SampleSet", value: [3, 4, 5, 6, 6, 7, 10, 15, 30] }, - { sampleCount: 100, xyPointLength: 100 } + env ); + let dist2 = new GenericDist( + { tag: "SampleSet", value: [20, 22, 24, 29, 30, 35, 38, 44, 52] }, + env + ); + test("mean", () => { expect(dist.mean().value).toBeCloseTo(3.737); }); @@ -63,4 +71,16 @@ describe("GenericDist", () => { test("toSparkline", () => { expect(dist.toSparkline(20).value).toBe("▁▁▃▅███▆▄▃▂▁▁▂▂▃▂▁▁▁"); }); + test("algebraicAdd", () => { + expect( + resultMap(dist.algebraicAdd(dist2), (r: GenericDist) => r.toSparkline(20)) + .value.value + ).toBe("▁▁▂▄▆████▇▆▄▄▃▃▃▂▁▁▁"); + }); + test("pointwiseAdd", () => { + expect( + resultMap(dist.pointwiseAdd(dist2), (r: GenericDist) => r.toSparkline(20)) + .value.value + ).toBe("▁▂▅██▅▅▅▆▇█▆▅▃▃▂▂▁▁▁"); + }); }); diff --git a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res index 12b94bcc..11e7f190 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res +++ b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res @@ -221,7 +221,7 @@ module Constructors = { let pointwiseSubtract = (~env, dist1, dist2) => C.pointwiseSubtract(dist1, dist2)->run(~env)->toDistR let pointwiseLogarithm = (~env, dist1, dist2) => - C.pointwiseSubtract(dist1, dist2)->run(~env)->toDistR + C.pointwiseLogarithm(dist1, dist2)->run(~env)->toDistR let pointwiseExponentiate = (~env, dist1, dist2) => - C.pointwiseSubtract(dist1, dist2)->run(~env)->toDistR + C.pointwiseExponentiate(dist1, dist2)->run(~env)->toDistR } diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res index 4815e98c..c321dc4a 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res @@ -10,7 +10,7 @@ let sampleN = (t: t, n) => switch t { | PointSet(r) => Ok(PointSetDist.sampleNRendered(n, r)) | Symbolic(r) => Ok(SymbolicDist.T.sampleN(n, r)) - | SampleSet(_) => Error(GenericDist_Types.NotYetImplemented) + | SampleSet(r) => Ok(SampleSet.sampleN(r, n)) } let fromFloat = (f: float): t => Symbolic(SymbolicDist.Float.make(f)) @@ -83,8 +83,10 @@ let toPointSet = ( let toSparkline = (t: t, ~sampleCount: int, ~buckets: int=20, unit): result => t - ->toPointSet(~xSelection=#Linear, ~xyPointLength=buckets*3, ~sampleCount, ()) - ->E.R.bind(r => r->PointSetDist.toSparkline(buckets)->E.R2.errMap(r => Error(GenericDist_Types.Other(r)))) + ->toPointSet(~xSelection=#Linear, ~xyPointLength=buckets * 3, ~sampleCount, ()) + ->E.R.bind(r => + r->PointSetDist.toSparkline(buckets)->E.R2.errMap(r => Error(GenericDist_Types.Other(r))) + ) module Truncate = { let trySymbolicSimplification = (leftCutoff, rightCutoff, t: t): option => diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res index 1bfb3e82..b0a30d52 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res @@ -140,7 +140,7 @@ module Constructors = { dist1, ) let pointwiseAdd = (dist1, dist2): t => FromDist( - ToDistCombination(Algebraic, #Add, #Dist(dist2)), + ToDistCombination(Pointwise, #Add, #Dist(dist2)), dist1, ) let pointwiseMultiply = (dist1, dist2): t => FromDist( diff --git a/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSet.res b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSet.res index 3c8f686a..07855686 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSet.res +++ b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSet.res @@ -60,6 +60,7 @@ module Internals = { : { let _ = Js.Array.push(element, continuous) } + () }) (continuous, discrete) @@ -143,4 +144,17 @@ let toPointSetDist = ( } samplesParse +} + +let sample = (t: t): float => { + let i = E.Int.random(~min=0, ~max=E.A.length(t) - 1) + E.A.unsafe_get(t, i) +} + +let sampleN = (t: t, n) => { + if n <= E.A.length(t) { + E.A.slice(t, ~offset=0, ~len=n) + } else { + Belt.Array.makeBy(n, _ => sample(t)) + } } \ No newline at end of file diff --git a/packages/squiggle-lang/src/rescript/Utility/E.res b/packages/squiggle-lang/src/rescript/Utility/E.res index 01dbde7d..16d87896 100644 --- a/packages/squiggle-lang/src/rescript/Utility/E.res +++ b/packages/squiggle-lang/src/rescript/Utility/E.res @@ -24,6 +24,7 @@ module FloatFloatMap = { module Int = { let max = (i1: int, i2: int) => i1 > i2 ? i1 : i2 + let random = (~min, ~max) => Js.Math.random_int(min, max) } /* Utils */ module U = { @@ -277,6 +278,7 @@ module A = { let fold_right = Array.fold_right let concatMany = Belt.Array.concatMany let keepMap = Belt.Array.keepMap + let slice = Belt.Array.slice let init = Array.init let reduce = Belt.Array.reduce let reducei = Belt.Array.reduceWithIndex From 54b6b18d3a7d4c60e4755593c2c65495dbe145dc Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Fri, 8 Apr 2022 22:55:06 -0400 Subject: [PATCH 31/41] Cleanup and commenting for PR --- packages/squiggle-lang/src/js/index.ts | 23 ++---- .../DistributionOperation.res | 79 ++++++++++--------- .../Distributions/GenericDist/GenericDist.res | 12 ++- .../GenericDist/GenericDist.resi | 2 +- .../GenericDist/GenericDist_Types.res | 74 +++-------------- .../PointSetDist/PointSetDist.res | 4 +- .../Distributions/SampleSetDist/SampleSet.res | 11 ++- .../src/rescript/TSInterface.res | 21 ----- .../src/rescript/TypescriptInterface.res | 24 ++++++ 9 files changed, 105 insertions(+), 145 deletions(-) delete mode 100644 packages/squiggle-lang/src/rescript/TSInterface.res create mode 100644 packages/squiggle-lang/src/rescript/TypescriptInterface.res diff --git a/packages/squiggle-lang/src/js/index.ts b/packages/squiggle-lang/src/js/index.ts index b690d581..25515db6 100644 --- a/packages/squiggle-lang/src/js/index.ts +++ b/packages/squiggle-lang/src/js/index.ts @@ -9,12 +9,12 @@ export type { SamplingInputs, exportEnv, exportDistribution }; export type { t as DistPlus } from "../rescript/OldInterpreter/DistPlus.gen"; import { genericDist, + env, resultDist, resultFloat, resultString, -} from "../rescript/TSInterface.gen"; +} from "../rescript/TypescriptInterface.gen"; import { - env, Constructors_mean, Constructors_sample, Constructors_pdf, @@ -59,18 +59,9 @@ export function run( return runAll(squiggleString, si, env); } -export function resultMap( - r: - | { - tag: "Ok"; - value: any; - } - | { - tag: "Error"; - value: any; - }, - mapFn: any -): +//This is clearly not fully typed. I think later we should use a functional library to +// provide a better Either type and corresponding functions. +type result = | { tag: "Ok"; value: any; @@ -78,7 +69,9 @@ export function resultMap( | { tag: "Error"; value: any; - } { + }; + +export function resultMap(r: result, mapFn: any): result { if (r.tag === "Ok") { return { tag: "Ok", value: mapFn(r.value) }; } else { diff --git a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res index 11e7f190..a36674db 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res +++ b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res @@ -114,8 +114,8 @@ let rec run = (~env, functionCallInfo: functionCallInfo): outputType => { ->E.R2.fmap(r => Float(r)) ->OutputLocal.fromResult | ToString(ToString) => dist->GenericDist.toString->String - | ToString(ToSparkline(buckets)) => - GenericDist.toSparkline(dist, ~sampleCount, ~buckets, ()) + | ToString(ToSparkline(bucketCount)) => + GenericDist.toSparkline(dist, ~sampleCount, ~bucketCount, ()) ->E.R2.fmap(r => String(r)) ->OutputLocal.fromResult | ToDist(Inspect) => { @@ -186,42 +186,43 @@ module Output = { } } +// See comment above GenericDist_Types.Constructors to explain the purpose of this module. +// I tried having another internal module called UsingDists, similar to how its done in +// GenericDist_Types.Constructors. However, this broke GenType for me, so beware. module Constructors = { - module C = GenericDist_Types.Constructors.UsingDists; - open OutputLocal - let mean = (~env, dist) => C.mean(dist)->run(~env)->toFloatR - let sample = (~env, dist) => C.sample(dist)->run(~env)->toFloatR - let cdf = (~env, dist, f) => C.cdf(dist, f)->run(~env)->toFloatR - let inv = (~env, dist, f) => C.inv(dist, f)->run(~env)->toFloatR - let pdf = (~env, dist, f) => C.pdf(dist, f)->run(~env)->toFloatR - let normalize = (~env, dist) => C.normalize(dist)->run(~env)->toDistR - let toPointSet = (~env, dist) => C.toPointSet(dist)->run(~env)->toDistR - let toSampleSet = (~env, dist, n) => C.toSampleSet(dist, n)->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 - let toString = (~env, dist) => C.toString(dist)->run(~env)->toStringR - let toSparkline = (~env, dist, buckets) => C.toSparkline(dist, buckets)->run(~env)->toStringR - let algebraicAdd = (~env, dist1, dist2) => C.algebraicAdd(dist1, dist2)->run(~env)->toDistR - let algebraicMultiply = (~env, dist1, dist2) => - C.algebraicMultiply(dist1, dist2)->run(~env)->toDistR - let algebraicDivide = (~env, dist1, dist2) => - C.algebraicDivide(dist1, dist2)->run(~env)->toDistR - let algebraicSubtract = (~env, dist1, dist2) => - C.algebraicSubtract(dist1, dist2)->run(~env)->toDistR - let algebraicLogarithm = (~env, dist1, dist2) => - C.algebraicLogarithm(dist1, dist2)->run(~env)->toDistR - let algebraicExponentiate = (~env, dist1, dist2) => - C.algebraicExponentiate(dist1, dist2)->run(~env)->toDistR - let pointwiseAdd = (~env, dist1, dist2) => C.pointwiseAdd(dist1, dist2)->run(~env)->toDistR - let pointwiseMultiply = (~env, dist1, dist2) => - C.pointwiseMultiply(dist1, dist2)->run(~env)->toDistR - let pointwiseDivide = (~env, dist1, dist2) => - C.pointwiseDivide(dist1, dist2)->run(~env)->toDistR - let pointwiseSubtract = (~env, dist1, dist2) => - C.pointwiseSubtract(dist1, dist2)->run(~env)->toDistR - let pointwiseLogarithm = (~env, dist1, dist2) => - C.pointwiseLogarithm(dist1, dist2)->run(~env)->toDistR - let pointwiseExponentiate = (~env, dist1, dist2) => - C.pointwiseExponentiate(dist1, dist2)->run(~env)->toDistR + module C = GenericDist_Types.Constructors.UsingDists + open OutputLocal + let mean = (~env, dist) => C.mean(dist)->run(~env)->toFloatR + let sample = (~env, dist) => C.sample(dist)->run(~env)->toFloatR + let cdf = (~env, dist, f) => C.cdf(dist, f)->run(~env)->toFloatR + let inv = (~env, dist, f) => C.inv(dist, f)->run(~env)->toFloatR + let pdf = (~env, dist, f) => C.pdf(dist, f)->run(~env)->toFloatR + let normalize = (~env, dist) => C.normalize(dist)->run(~env)->toDistR + let toPointSet = (~env, dist) => C.toPointSet(dist)->run(~env)->toDistR + let toSampleSet = (~env, dist, n) => C.toSampleSet(dist, n)->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 + let toString = (~env, dist) => C.toString(dist)->run(~env)->toStringR + let toSparkline = (~env, dist, bucketCount) => C.toSparkline(dist, bucketCount)->run(~env)->toStringR + let algebraicAdd = (~env, dist1, dist2) => C.algebraicAdd(dist1, dist2)->run(~env)->toDistR + let algebraicMultiply = (~env, dist1, dist2) => + C.algebraicMultiply(dist1, dist2)->run(~env)->toDistR + let algebraicDivide = (~env, dist1, dist2) => C.algebraicDivide(dist1, dist2)->run(~env)->toDistR + let algebraicSubtract = (~env, dist1, dist2) => + C.algebraicSubtract(dist1, dist2)->run(~env)->toDistR + let algebraicLogarithm = (~env, dist1, dist2) => + C.algebraicLogarithm(dist1, dist2)->run(~env)->toDistR + let algebraicExponentiate = (~env, dist1, dist2) => + C.algebraicExponentiate(dist1, dist2)->run(~env)->toDistR + let pointwiseAdd = (~env, dist1, dist2) => C.pointwiseAdd(dist1, dist2)->run(~env)->toDistR + let pointwiseMultiply = (~env, dist1, dist2) => + C.pointwiseMultiply(dist1, dist2)->run(~env)->toDistR + let pointwiseDivide = (~env, dist1, dist2) => C.pointwiseDivide(dist1, dist2)->run(~env)->toDistR + let pointwiseSubtract = (~env, dist1, dist2) => + C.pointwiseSubtract(dist1, dist2)->run(~env)->toDistR + let pointwiseLogarithm = (~env, dist1, dist2) => + C.pointwiseLogarithm(dist1, dist2)->run(~env)->toDistR + let pointwiseExponentiate = (~env, dist1, dist2) => + C.pointwiseExponentiate(dist1, dist2)->run(~env)->toDistR } diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res index c321dc4a..6bcbb221 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res @@ -81,11 +81,17 @@ let toPointSet = ( } } -let toSparkline = (t: t, ~sampleCount: int, ~buckets: int=20, unit): result => +/* + PointSetDist.toSparkline calls "downsampleEquallyOverX", which downsamples it to n=bucketCount. + It first needs a pointSetDist, so we convert to a pointSetDist. In this process we want the + xyPointLength to be a bit longer than the eventual toSparkline downsampling. I chose 3 + fairly arbitrarily. + */ +let toSparkline = (t: t, ~sampleCount: int, ~bucketCount: int=20, unit): result => t - ->toPointSet(~xSelection=#Linear, ~xyPointLength=buckets * 3, ~sampleCount, ()) + ->toPointSet(~xSelection=#Linear, ~xyPointLength=bucketCount * 3, ~sampleCount, ()) ->E.R.bind(r => - r->PointSetDist.toSparkline(buckets)->E.R2.errMap(r => Error(GenericDist_Types.Other(r))) + r->PointSetDist.toSparkline(bucketCount)->E.R2.errMap(r => Error(GenericDist_Types.Other(r))) ) module Truncate = { diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi index 5fa24de9..adf3b9d4 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi @@ -26,7 +26,7 @@ let toPointSet: ( ~xSelection: GenericDist_Types.Operation.pointsetXSelection=?, unit, ) => result -let toSparkline: (t, ~sampleCount: int, ~buckets: int=?, unit) => result +let toSparkline: (t, ~sampleCount: int, ~bucketCount: int=?, unit) => result let truncate: ( t, diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res index b0a30d52..b3aeddac 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res @@ -98,6 +98,14 @@ module Operation = { } } +/* +It can be a pain to write out the genericFunctionCallInfo. The constructors help with this. +This code only covers some of genericFunctionCallInfo: many arguments could be called with either a +float or a distribution. The "UsingDists" module assumes that everything is a distribution. +This is a tradeoff of some generality in order to get a bit more simplicity. +I could see having a longer interface in the future, but it could be messy. +Like, algebraicAddDistFloat vs. algebraicAddDistDist +*/ module Constructors = { type t = Operation.genericFunctionCallInfo @@ -105,9 +113,9 @@ module Constructors = { @genType let mean = (dist): t => FromDist(ToFloat(#Mean), dist) let sample = (dist): t => FromDist(ToFloat(#Sample), dist) - let cdf = (dist, f): t => FromDist(ToFloat(#Cdf(f)), dist) - let inv = (dist, f): t => FromDist(ToFloat(#Inv(f)), dist) - let pdf = (dist, f): t => FromDist(ToFloat(#Pdf(f)), dist) + let cdf = (dist, x): t => FromDist(ToFloat(#Cdf(x)), dist) + let inv = (dist, x): t => FromDist(ToFloat(#Inv(x)), dist) + let pdf = (dist, x): t => FromDist(ToFloat(#Pdf(x)), dist) let normalize = (dist): t => FromDist(ToDist(Normalize), dist) let toPointSet = (dist): t => FromDist(ToDist(ToPointSet), dist) let toSampleSet = (dist, r): t => FromDist(ToDist(ToSampleSet(r)), dist) @@ -165,63 +173,3 @@ module Constructors = { ) } } - -module DistVariant = { - type t = - | Mean(genericDist) - | Sample(genericDist) - | Cdf(genericDist, float) - | Inv(genericDist, float) - | Pdf(genericDist, float) - | Normalize(genericDist) - | ToPointSet(genericDist) - | ToSampleSet(genericDist, int) - | Truncate(genericDist, option, option) - | Inspect(genericDist) - | ToString(genericDist) - | ToSparkline(genericDist, int) - | AlgebraicAdd(genericDist, genericDist) - | AlgebraicMultiply(genericDist, genericDist) - | AlgebraicDivide(genericDist, genericDist) - | AlgebraicSubtract(genericDist, genericDist) - | AlgebraicLogarithm(genericDist, genericDist) - | AlgebraicExponentiate(genericDist, genericDist) - | PointwiseAdd(genericDist, genericDist) - | PointwiseMultiply(genericDist, genericDist) - | PointwiseDivide(genericDist, genericDist) - | PointwiseSubtract(genericDist, genericDist) - | PointwiseLogarithm(genericDist, genericDist) - | PointwiseExponentiate(genericDist, genericDist) - - let toGenericFunctionCallInfo = (t: t) => - switch t { - | Mean(d) => Operation.FromDist(ToFloat(#Mean), d) - | Sample(d) => FromDist(ToFloat(#Mean), d) - | Cdf(d, f) => FromDist(ToFloat(#Cdf(f)), d) - | Inv(d, f) => FromDist(ToFloat(#Inv(f)), d) - | Pdf(d, f) => FromDist(ToFloat(#Pdf(f)), d) - | Normalize(d) => FromDist(ToDist(Normalize), d) - | ToPointSet(d) => FromDist(ToDist(ToPointSet), d) - | ToSampleSet(d, r) => FromDist(ToDist(ToSampleSet(r)), d) - | Truncate(d, left, right) => FromDist(ToDist(Truncate(left, right)), d) - | Inspect(d) => FromDist(ToDist(Inspect), d) - | ToString(d) => FromDist(ToString(ToString), d) - | ToSparkline(d, n) => FromDist(ToString(ToSparkline(n)), d) - | AlgebraicAdd(d1, d2) => FromDist(ToDistCombination(Algebraic, #Add, #Dist(d2)), d1) - | AlgebraicMultiply(d1, d2) => FromDist(ToDistCombination(Algebraic, #Multiply, #Dist(d2)), d1) - | AlgebraicDivide(d1, d2) => FromDist(ToDistCombination(Algebraic, #Divide, #Dist(d2)), d1) - | AlgebraicSubtract(d1, d2) => FromDist(ToDistCombination(Algebraic, #Subtract, #Dist(d2)), d1) - | AlgebraicLogarithm(d1, d2) => - FromDist(ToDistCombination(Algebraic, #Logarithm, #Dist(d2)), d1) - | AlgebraicExponentiate(d1, d2) => - FromDist(ToDistCombination(Algebraic, #Exponentiate, #Dist(d2)), d1) - | PointwiseAdd(d1, d2) => FromDist(ToDistCombination(Pointwise, #Add, #Dist(d2)), d1) - | PointwiseMultiply(d1, d2) => FromDist(ToDistCombination(Pointwise, #Multiply, #Dist(d2)), d1) - | PointwiseDivide(d1, d2) => FromDist(ToDistCombination(Pointwise, #Divide, #Dist(d2)), d1) - | PointwiseSubtract(d1, d2) => FromDist(ToDistCombination(Pointwise, #Subtract, #Dist(d2)), d1) - | PointwiseLogarithm(d1, d2) => - FromDist(ToDistCombination(Pointwise, #Logarithm, #Dist(d2)), d1) - | PointwiseExponentiate(d1, d2) => - FromDist(ToDistCombination(Pointwise, #Exponentiate, #Dist(d2)), d1) - } -} \ No newline at end of file diff --git a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res index c7bec8a9..f3f3c20c 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res @@ -203,8 +203,8 @@ let operate = (distToFloatOp: Operation.distToFloatOperation, s): float => | #Mean => T.mean(s) } -let toSparkline = (t: t, n) => +let toSparkline = (t: t, bucketCount) => T.toContinuous(t) - ->E.O2.fmap(Continuous.downsampleEquallyOverX(n)) + ->E.O2.fmap(Continuous.downsampleEquallyOverX(bucketCount)) ->E.O2.toResult("toContinous Error: Could not convert into continuous distribution") ->E.R2.fmap(r => Continuous.getShape(r).ys->Sparklines.create()) \ No newline at end of file diff --git a/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSet.res b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSet.res index 07855686..f8bce6f6 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSet.res +++ b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSet.res @@ -146,15 +146,24 @@ let toPointSetDist = ( samplesParse } +//Randomly get one sample from the distribution let sample = (t: t): float => { let i = E.Int.random(~min=0, ~max=E.A.length(t) - 1) E.A.unsafe_get(t, i) } +/* +If asked for a length of samples shorter or equal the length of the distribution, +return this first n samples of this distribution. +Else, return n random samples of the distribution. +The former helps in cases where multiple distributions are correlated. +However, if n > length(t), then there's no clear right answer, so we just randomly +sample everything. +*/ let sampleN = (t: t, n) => { if n <= E.A.length(t) { E.A.slice(t, ~offset=0, ~len=n) } else { Belt.Array.makeBy(n, _ => sample(t)) } -} \ No newline at end of file +} diff --git a/packages/squiggle-lang/src/rescript/TSInterface.res b/packages/squiggle-lang/src/rescript/TSInterface.res deleted file mode 100644 index 26b694a5..00000000 --- a/packages/squiggle-lang/src/rescript/TSInterface.res +++ /dev/null @@ -1,21 +0,0 @@ -@genType -type functionCallInfo = GenericDist_Types.Operation.genericFunctionCallInfo; - -@genType -type env = DistributionOperation.env; - -@genType -type genericDist = GenericDist_Types.genericDist; - -@genType -type error = GenericDist_Types.error; - -@genType -let runDistributionOperation = DistributionOperation.run; - -@genType -type resultDist = result -@genType -type resultFloat = result -@genType -type resultString = result \ No newline at end of file diff --git a/packages/squiggle-lang/src/rescript/TypescriptInterface.res b/packages/squiggle-lang/src/rescript/TypescriptInterface.res new file mode 100644 index 00000000..fb30ea24 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/TypescriptInterface.res @@ -0,0 +1,24 @@ +/* +This is meant as a file to contain @genType declarations as needed for Typescript. +I would ultimately want to have all @genType declarations here, vs. other files, but +@genType doesn't play as nicely with renaming Modules and functions as +would be preferable. + +The below few seem to work fine. In the future there's definitely more work to do here. +*/ + +@genType +type env = DistributionOperation.env + +@genType +type genericDist = GenericDist_Types.genericDist + +@genType +type error = GenericDist_Types.error + +@genType +type resultDist = result +@genType +type resultFloat = result +@genType +type resultString = result From 9430653b7a14cbd86c2ae9535f6f34f3ffba8029 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Sat, 9 Apr 2022 12:37:26 -0400 Subject: [PATCH 32/41] Namechange: Exponential -> Power --- packages/squiggle-lang/src/js/index.ts | 12 +++++------ .../DistributionOperation.res | 8 ++++---- .../DistributionOperation.resi | 4 ++-- .../Distributions/DistributionTypes.res | 4 ++-- .../Distributions/GenericDist/GenericDist.res | 2 +- .../GenericDist/GenericDist_Types.res | 12 +++++------ .../AlgebraicShapeCombination.res | 6 +++--- .../rescript/OldInterpreter/ASTEvaluator.res | 2 +- .../typeSystem/HardcodedFunctions.res | 2 +- .../src/rescript/OldParser/Parser.res | 4 ++-- .../ReducerInterface_GenericDistribution.res | 4 ++-- .../src/rescript/Utility/Operation.res | 20 +++++++++---------- 12 files changed, 40 insertions(+), 40 deletions(-) diff --git a/packages/squiggle-lang/src/js/index.ts b/packages/squiggle-lang/src/js/index.ts index 25515db6..1f67e369 100644 --- a/packages/squiggle-lang/src/js/index.ts +++ b/packages/squiggle-lang/src/js/index.ts @@ -32,13 +32,13 @@ import { Constructors_algebraicDivide, Constructors_algebraicSubtract, Constructors_algebraicLogarithm, - Constructors_algebraicExponentiate, + Constructors_algebraicPower, Constructors_pointwiseAdd, Constructors_pointwiseMultiply, Constructors_pointwiseDivide, Constructors_pointwiseSubtract, Constructors_pointwiseLogarithm, - Constructors_pointwiseExponentiate, + Constructors_pointwisePower, } from "../rescript/Distributions/DistributionOperation/DistributionOperation.gen"; export let defaultSamplingInputs: SamplingInputs = { @@ -179,9 +179,9 @@ export class GenericDist { ); } - algebraicExponentiate(d2: GenericDist) { + algebraicPower(d2: GenericDist) { return this.mapResultDist( - Constructors_algebraicExponentiate({ env: this.env }, this.t, d2.t) + Constructors_algebraicPower({ env: this.env }, this.t, d2.t) ); } @@ -215,9 +215,9 @@ export class GenericDist { ); } - pointwiseExponentiate(d2: GenericDist) { + pointwisePower(d2: GenericDist) { return this.mapResultDist( - Constructors_pointwiseExponentiate({ env: this.env }, this.t, d2.t) + Constructors_pointwisePower({ env: this.env }, this.t, d2.t) ); } } diff --git a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res index a36674db..69a9a4ed 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res +++ b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res @@ -213,8 +213,8 @@ module Constructors = { C.algebraicSubtract(dist1, dist2)->run(~env)->toDistR let algebraicLogarithm = (~env, dist1, dist2) => C.algebraicLogarithm(dist1, dist2)->run(~env)->toDistR - let algebraicExponentiate = (~env, dist1, dist2) => - C.algebraicExponentiate(dist1, dist2)->run(~env)->toDistR + let algebraicPower = (~env, dist1, dist2) => + C.algebraicPower(dist1, dist2)->run(~env)->toDistR let pointwiseAdd = (~env, dist1, dist2) => C.pointwiseAdd(dist1, dist2)->run(~env)->toDistR let pointwiseMultiply = (~env, dist1, dist2) => C.pointwiseMultiply(dist1, dist2)->run(~env)->toDistR @@ -223,6 +223,6 @@ module Constructors = { C.pointwiseSubtract(dist1, dist2)->run(~env)->toDistR let pointwiseLogarithm = (~env, dist1, dist2) => C.pointwiseLogarithm(dist1, dist2)->run(~env)->toDistR - let pointwiseExponentiate = (~env, dist1, dist2) => - C.pointwiseExponentiate(dist1, dist2)->run(~env)->toDistR + let pointwisePower = (~env, dist1, dist2) => + C.pointwisePower(dist1, dist2)->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 ce0fca72..bfe45013 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.resi +++ b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.resi @@ -79,7 +79,7 @@ module Constructors: { @genType let algebraicLogarithm: (~env: env, genericDist, genericDist) => result @genType - let algebraicExponentiate: (~env: env, genericDist, genericDist) => result + let algebraicPower: (~env: env, genericDist, genericDist) => result @genType let pointwiseAdd: (~env: env, genericDist, genericDist) => result @genType @@ -91,5 +91,5 @@ module Constructors: { @genType let pointwiseLogarithm: (~env: env, genericDist, genericDist) => result @genType - let pointwiseExponentiate: (~env: env, genericDist, genericDist) => result + let pointwisePower: (~env: env, genericDist, genericDist) => result } diff --git a/packages/squiggle-lang/src/rescript/Distributions/DistributionTypes.res b/packages/squiggle-lang/src/rescript/Distributions/DistributionTypes.res index a3e249d3..cab58839 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/DistributionTypes.res +++ b/packages/squiggle-lang/src/rescript/Distributions/DistributionTypes.res @@ -19,7 +19,7 @@ module Operation = { | #Multiply | #Subtract | #Divide - | #Exponentiate + | #Power | #Logarithm ] @@ -28,7 +28,7 @@ module Operation = { | #Add => \"+." | #Multiply => \"*." | #Subtract => \"-." - | #Exponentiate => \"**" + | #Power => \"**" | #Divide => \"/." | #Logarithm => (a, b) => log(a) /. log(b) } diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res index 6bcbb221..ba19e60b 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res @@ -247,7 +247,7 @@ let pointwiseCombinationFloat = ( ): result => { let m = switch arithmeticOperation { | #Add | #Subtract => Error(GenericDist_Types.DistributionVerticalShiftIsInvalid) - | (#Multiply | #Divide | #Exponentiate | #Logarithm) as arithmeticOperation => + | (#Multiply | #Divide | #Power | #Logarithm) as arithmeticOperation => toPointSetFn(t)->E.R2.fmap(t => { //TODO: Move to PointSet codebase let fn = (secondary, main) => Operation.Scale.toFn(arithmeticOperation, main, secondary) diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res index b3aeddac..70754807 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res @@ -20,7 +20,7 @@ module Operation = { | #Multiply | #Subtract | #Divide - | #Exponentiate + | #Power | #Logarithm ] @@ -29,7 +29,7 @@ module Operation = { | #Add => \"+." | #Multiply => \"*." | #Subtract => \"-." - | #Exponentiate => \"**" + | #Power => \"**" | #Divide => \"/." | #Logarithm => (a, b) => log(a) /. log(b) } @@ -143,8 +143,8 @@ module Constructors = { ToDistCombination(Algebraic, #Logarithm, #Dist(dist2)), dist1, ) - let algebraicExponentiate = (dist1, dist2): t => FromDist( - ToDistCombination(Algebraic, #Exponentiate, #Dist(dist2)), + let algebraicPower = (dist1, dist2): t => FromDist( + ToDistCombination(Algebraic, #Power, #Dist(dist2)), dist1, ) let pointwiseAdd = (dist1, dist2): t => FromDist( @@ -167,8 +167,8 @@ module Constructors = { ToDistCombination(Pointwise, #Logarithm, #Dist(dist2)), dist1, ) - let pointwiseExponentiate = (dist1, dist2): t => FromDist( - ToDistCombination(Pointwise, #Exponentiate, #Dist(dist2)), + let pointwisePower = (dist1, dist2): t => FromDist( + ToDistCombination(Pointwise, #Power, #Dist(dist2)), dist1, ) } diff --git a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/AlgebraicShapeCombination.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/AlgebraicShapeCombination.res index c0d85e60..70440878 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/AlgebraicShapeCombination.res +++ b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/AlgebraicShapeCombination.res @@ -114,7 +114,7 @@ let combineShapesContinuousContinuous = ( | #Subtract => (m1, m2) => m1 -. m2 | #Multiply => (m1, m2) => m1 *. m2 | #Divide => (m1, mInv2) => m1 *. mInv2 - | #Exponentiate => (m1, mInv2) => m1 ** mInv2 + | #Power => (m1, mInv2) => m1 ** mInv2 | #Logarithm => (m1, m2) => log(m1) /. log(m2) } // note: here, mInv2 = mean(1 / t2) ~= 1 / mean(t2) @@ -124,7 +124,7 @@ let combineShapesContinuousContinuous = ( | #Add => (v1, v2, _, _) => v1 +. v2 | #Subtract => (v1, v2, _, _) => v1 +. v2 | #Multiply => (v1, v2, m1, m2) => v1 *. v2 +. v1 *. m2 ** 2. +. v2 *. m1 ** 2. - | #Exponentiate => (v1, v2, m1, m2) => v1 *. v2 +. v1 *. m2 ** 2. +. v2 *. m1 ** 2. + | #Power => (v1, v2, m1, m2) => v1 *. v2 +. v1 *. m2 ** 2. +. v2 *. m1 ** 2. | #Logarithm => (v1, v2, m1, m2) => v1 *. v2 +. v1 *. m2 ** 2. +. v2 *. m1 ** 2. | #Divide => (v1, vInv2, m1, mInv2) => v1 *. vInv2 +. v1 *. mInv2 ** 2. +. vInv2 *. m1 ** 2. } @@ -233,7 +233,7 @@ let combineShapesContinuousDiscrete = ( () } | #Multiply - | #Exponentiate + | #Power | #Logarithm | #Divide => for j in 0 to t2n - 1 { diff --git a/packages/squiggle-lang/src/rescript/OldInterpreter/ASTEvaluator.res b/packages/squiggle-lang/src/rescript/OldInterpreter/ASTEvaluator.res index 44c5565e..cd4c241d 100644 --- a/packages/squiggle-lang/src/rescript/OldInterpreter/ASTEvaluator.res +++ b/packages/squiggle-lang/src/rescript/OldInterpreter/ASTEvaluator.res @@ -118,7 +118,7 @@ module PointwiseCombination = { switch pointwiseOp { | #Add => pointwiseAdd(evaluationParams, t1, t2) | #Multiply => pointwiseCombine(\"*.", evaluationParams, t1, t2) - | #Exponentiate => pointwiseCombine(\"**", evaluationParams, t1, t2) + | #Power => pointwiseCombine(\"**", evaluationParams, t1, t2) } } diff --git a/packages/squiggle-lang/src/rescript/OldInterpreter/typeSystem/HardcodedFunctions.res b/packages/squiggle-lang/src/rescript/OldInterpreter/typeSystem/HardcodedFunctions.res index cf8fe470..8302b532 100644 --- a/packages/squiggle-lang/src/rescript/OldInterpreter/typeSystem/HardcodedFunctions.res +++ b/packages/squiggle-lang/src/rescript/OldInterpreter/typeSystem/HardcodedFunctions.res @@ -227,7 +227,7 @@ let all = [ }, (), ), - makeRenderedDistFloat("scaleExp", (dist, float) => verticalScaling(#Exponentiate, dist, float)), + makeRenderedDistFloat("scaleExp", (dist, float) => verticalScaling(#Power, dist, float)), makeRenderedDistFloat("scaleMultiply", (dist, float) => verticalScaling(#Multiply, dist, float)), makeRenderedDistFloat("scaleLog", (dist, float) => verticalScaling(#Logarithm, dist, float)), Multimodal._function, diff --git a/packages/squiggle-lang/src/rescript/OldParser/Parser.res b/packages/squiggle-lang/src/rescript/OldParser/Parser.res index 0a837823..6f5fd9ef 100644 --- a/packages/squiggle-lang/src/rescript/OldParser/Parser.res +++ b/packages/squiggle-lang/src/rescript/OldParser/Parser.res @@ -144,11 +144,11 @@ module MathAdtToDistDst = { | ("subtract", _) => Error("Subtraction needs two operands") | ("multiply", [l, r]) => toOkAlgebraic((#Multiply, l, r)) | ("multiply", _) => Error("Multiplication needs two operands") - | ("pow", [l, r]) => toOkAlgebraic((#Exponentiate, l, r)) + | ("pow", [l, r]) => toOkAlgebraic((#Power, l, r)) | ("pow", _) => Error("Exponentiation needs two operands") | ("dotMultiply", [l, r]) => toOkPointwise((#Multiply, l, r)) | ("dotMultiply", _) => Error("Dotwise multiplication needs two operands") - | ("dotPow", [l, r]) => toOkPointwise((#Exponentiate, l, r)) + | ("dotPow", [l, r]) => toOkPointwise((#Power, l, r)) | ("dotPow", _) => Error("Dotwise exponentiation needs two operands") | ("rightLogShift", [l, r]) => toOkPointwise((#Add, l, r)) | ("rightLogShift", _) => Error("Dotwise addition needs two operands") diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res index 89be2d46..ea65b963 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res @@ -18,8 +18,8 @@ module Helpers = { | "divide" => #Divide | "log" => #Logarithm | "dotDivide" => #Divide - | "pow" => #Exponentiate - | "dotPow" => #Exponentiate + | "pow" => #Power + | "dotPow" => #Power | "multiply" => #Multiply | "dotMultiply" => #Multiply | "dotLog" => #Logarithm diff --git a/packages/squiggle-lang/src/rescript/Utility/Operation.res b/packages/squiggle-lang/src/rescript/Utility/Operation.res index 55e0b42f..5145955c 100644 --- a/packages/squiggle-lang/src/rescript/Utility/Operation.res +++ b/packages/squiggle-lang/src/rescript/Utility/Operation.res @@ -6,12 +6,12 @@ type algebraicOperation = [ | #Multiply | #Subtract | #Divide - | #Exponentiate + | #Power | #Logarithm ] @genType -type pointwiseOperation = [#Add | #Multiply | #Exponentiate] -type scaleOperation = [#Multiply | #Exponentiate | #Logarithm | #Divide] +type pointwiseOperation = [#Add | #Multiply | #Power] +type scaleOperation = [#Multiply | #Power | #Logarithm | #Divide] type distToFloatOperation = [ | #Pdf(float) | #Cdf(float) @@ -27,7 +27,7 @@ module Algebraic = { | #Add => \"+." | #Subtract => \"-." | #Multiply => \"*." - | #Exponentiate => \"**" + | #Power => \"**" | #Divide => \"/." | #Logarithm => (a, b) => log(a) /. log(b) } @@ -43,7 +43,7 @@ module Algebraic = { | #Add => "+" | #Subtract => "-" | #Multiply => "*" - | #Exponentiate => "**" + | #Power => "**" | #Divide => "/" | #Logarithm => "log" } @@ -56,7 +56,7 @@ module Pointwise = { let toString = x => switch x { | #Add => "+" - | #Exponentiate => "^" + | #Power => "^" | #Multiply => "*" } @@ -83,7 +83,7 @@ module Scale = { switch x { | #Multiply => \"*." | #Divide => \"/." - | #Exponentiate => \"**" + | #Power => \"**" | #Logarithm => (a, b) => log(a) /. log(b) } @@ -91,7 +91,7 @@ module Scale = { switch operation { | #Multiply => j`verticalMultiply($value, $scaleBy) ` | #Divide => j`verticalDivide($value, $scaleBy) ` - | #Exponentiate => j`verticalExponentiate($value, $scaleBy) ` + | #Power => j`verticalPower($value, $scaleBy) ` | #Logarithm => j`verticalLog($value, $scaleBy) ` } @@ -99,7 +99,7 @@ module Scale = { switch x { | #Multiply => (a, b) => Some(a *. b) | #Divide => (a, b) => Some(a /. b) - | #Exponentiate => (_, _) => None + | #Power => (_, _) => None | #Logarithm => (_, _) => None } @@ -107,7 +107,7 @@ module Scale = { switch x { | #Multiply => (_, _) => None // TODO: this could probably just be multiplied out (using Continuous.scaleBy) | #Divide => (_, _) => None - | #Exponentiate => (_, _) => None + | #Power => (_, _) => None | #Logarithm => (_, _) => None } } From 61aaca3e2ff86a1e80e22b8c2654f72eea388490 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Sat, 9 Apr 2022 18:10:06 -0400 Subject: [PATCH 33/41] Gave SampleSetDist a private type --- .../DistributionOperation_test.res | 3 +- .../__tests__/Distributions/Samples_test.res | 8 ++-- .../DistributionOperation.res | 2 +- .../Distributions/GenericDist/GenericDist.res | 31 +++++++----- .../GenericDist/GenericDist.resi | 3 +- .../GenericDist/GenericDist_Types.res | 2 +- .../SampleSetDist/SampleSetDist.res | 48 +++++++++++++++++++ ...leSet.res => SampleSetDist_ToPointSet.res} | 27 ----------- .../src/rescript/OldInterpreter/ASTTypes.res | 14 +++--- 9 files changed, 83 insertions(+), 55 deletions(-) create mode 100644 packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist.res rename packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/{SampleSet.res => SampleSetDist_ToPointSet.res} (85%) diff --git a/packages/squiggle-lang/__tests__/Distributions/DistributionOperation_test.res b/packages/squiggle-lang/__tests__/Distributions/DistributionOperation_test.res index cd22d512..f206b31d 100644 --- a/packages/squiggle-lang/__tests__/Distributions/DistributionOperation_test.res +++ b/packages/squiggle-lang/__tests__/Distributions/DistributionOperation_test.res @@ -91,8 +91,9 @@ describe("toPointSet", () => { }) test("on sample set distribution with under 4 points", () => { + let sampleSet = SampleSetDist.make([0.0, 1.0, 2.0, 3.0]) -> E.R.toExn; let result = - run(FromDist(ToDist(ToPointSet), SampleSet([0.0, 1.0, 2.0, 3.0])))->outputMap( + run(FromDist(ToDist(ToPointSet), SampleSet(sampleSet)))->outputMap( FromDist(ToFloat(#Mean)), ) expect(result)->toEqual(GenDistError(Other("Converting sampleSet to pointSet failed"))) diff --git a/packages/squiggle-lang/__tests__/Distributions/Samples_test.res b/packages/squiggle-lang/__tests__/Distributions/Samples_test.res index db80f9f7..5a48dd80 100644 --- a/packages/squiggle-lang/__tests__/Distributions/Samples_test.res +++ b/packages/squiggle-lang/__tests__/Distributions/Samples_test.res @@ -4,12 +4,12 @@ open TestHelpers describe("Continuous and discrete splits", () => { makeTest( "splits (1)", - SampleSet.Internals.T.splitContinuousAndDiscrete([1.432, 1.33455, 2.0]), + SampleSetDist_ToPointSet.Internals.T.splitContinuousAndDiscrete([1.432, 1.33455, 2.0]), ([1.432, 1.33455, 2.0], E.FloatFloatMap.empty()), ) makeTest( "splits (2)", - SampleSet.Internals.T.splitContinuousAndDiscrete([ + SampleSetDist_ToPointSet.Internals.T.splitContinuousAndDiscrete([ 1.432, 1.33455, 2.0, @@ -26,13 +26,13 @@ describe("Continuous and discrete splits", () => { E.A.concatMany([sorted, sorted, sorted, sorted]) |> Belt.SortArray.stableSortBy(_, compare) } - let (_, discrete1) = SampleSet.Internals.T.splitContinuousAndDiscrete( + let (_, discrete1) = SampleSetDist_ToPointSet.Internals.T.splitContinuousAndDiscrete( makeDuplicatedArray(10), ) let toArr1 = discrete1 |> E.FloatFloatMap.toArray makeTest("splitMedium at count=10", toArr1 |> Belt.Array.length, 10) - let (_c, discrete2) = SampleSet.Internals.T.splitContinuousAndDiscrete( + let (_c, discrete2) = SampleSetDist_ToPointSet.Internals.T.splitContinuousAndDiscrete( makeDuplicatedArray(500), ) let toArr2 = discrete2 |> E.FloatFloatMap.toArray diff --git a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res index 69a9a4ed..bb5f4f1a 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res +++ b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res @@ -128,7 +128,7 @@ let rec run = (~env, functionCallInfo: functionCallInfo): outputType => { ->E.R2.fmap(r => Dist(r)) ->OutputLocal.fromResult | ToDist(ToSampleSet(n)) => - dist->GenericDist.sampleN(n)->E.R2.fmap(r => Dist(SampleSet(r)))->OutputLocal.fromResult + dist->GenericDist.toSampleSetDist(n)->E.R2.fmap(r => Dist(SampleSet(r)))->OutputLocal.fromResult | ToDist(ToPointSet) => dist ->GenericDist.toPointSet(~xyPointLength, ~sampleCount, ()) diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res index ba19e60b..90381fba 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res @@ -2,16 +2,18 @@ type t = GenericDist_Types.genericDist type error = GenericDist_Types.error type toPointSetFn = t => result -type toSampleSetFn = t => result, error> +type toSampleSetFn = t => result type scaleMultiplyFn = (t, float) => result type pointwiseAddFn = (t, t) => result - +let mapStringErrors = n => n->E.R2.errMap(r => Error(GenericDist_Types.Other(r))) let sampleN = (t: t, n) => switch t { | PointSet(r) => Ok(PointSetDist.sampleNRendered(n, r)) | Symbolic(r) => Ok(SymbolicDist.T.sampleN(n, r)) - | SampleSet(r) => Ok(SampleSet.sampleN(r, n)) + | SampleSet(r) => Ok(SampleSetDist.sampleN(r, n)) } +let toSampleSetDist = (t: t, n) => sampleN(t, n)->E.R.bind(SampleSetDist.make)->mapStringErrors +let mapStringErrors = n => n->E.R2.errMap(r => Error(GenericDist_Types.Other(r))) let fromFloat = (f: float): t => Symbolic(SymbolicDist.Float.make(f)) @@ -63,7 +65,7 @@ let toPointSet = ( | PointSet(pointSet) => Ok(pointSet) | Symbolic(r) => Ok(SymbolicDist.T.toPointSetDist(~xSelection, xyPointLength, r)) | SampleSet(r) => { - let response = SampleSet.toPointSetDist( + let response = SampleSetDist.toPointSetDist( ~samples=r, ~samplingInputs={ sampleCount: sampleCount, @@ -167,8 +169,9 @@ module AlgebraicCombination = { t2: t, ) => { let arithmeticOperation = Operation.Algebraic.toFn(arithmeticOperation) - E.R.merge(toSampleSet(t1), toSampleSet(t2))->E.R2.fmap(((a, b)) => { - Belt.Array.zip(a, b)->E.A2.fmap(((a, b)) => arithmeticOperation(a, b)) + E.R.merge(toSampleSet(t1), toSampleSet(t2))->E.R.bind(((a, b)) => { + SampleSetDist.runMonteCarlo(arithmeticOperation, a, b) + ->mapStringErrors }) } @@ -200,13 +203,15 @@ module AlgebraicCombination = { | Some(Error(e)) => Error(Other(e)) | None => switch chooseConvolutionOrMonteCarlo(t1, t2) { - | #CalculateWithMonteCarlo => - runMonteCarlo( - toSampleSetFn, - arithmeticOperation, - t1, - t2, - )->E.R2.fmap(r => GenericDist_Types.SampleSet(r)) + | #CalculateWithMonteCarlo => { + let sampleSetDist: result = runMonteCarlo( + toSampleSetFn, + arithmeticOperation, + t1, + t2, + ) + sampleSetDist->E.R2.fmap(r => GenericDist_Types.SampleSet(r)) + } | #CalculateWithConvolution => runConvolution( toPointSetFn, diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi index adf3b9d4..b65489e3 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi @@ -1,11 +1,12 @@ type t = GenericDist_Types.genericDist type error = GenericDist_Types.error type toPointSetFn = t => result -type toSampleSetFn = t => result, error> +type toSampleSetFn = t => result type scaleMultiplyFn = (t, float) => result type pointwiseAddFn = (t, t) => result let sampleN: (t, int) => result, error> +let toSampleSetDist: (t, int) => Belt.Result.t let fromFloat: float => t diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res index 70754807..c3c923a4 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res @@ -1,6 +1,6 @@ type genericDist = | PointSet(PointSetTypes.pointSetDist) - | SampleSet(SampleSet.t) + | SampleSet(SampleSetDist.t) | Symbolic(SymbolicDistTypes.symbolicDist) @genType diff --git a/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist.res b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist.res new file mode 100644 index 00000000..cea650f8 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist.res @@ -0,0 +1,48 @@ +module T: { + type t + let make: array => result + let get: t => array +} = { + type t = array + let make = (a: array) => + if E.A.length(a) > 5 { + Ok(a) + } else { + Error("too small") + } + let get = (a: t) => a +} + +include T + +// TODO: Refactor to raise correct error when not enough samples + +let toPointSetDist = (~samples: t, ~samplingInputs: SamplingInputs.samplingInputs, ()) => + SampleSetDist_ToPointSet.toPointSetDist(~samples=get(samples), ~samplingInputs, ()) + +//Randomly get one sample from the distribution +let sample = (t: t): float => { + let i = E.Int.random(~min=0, ~max=E.A.length(get(t)) - 1) + E.A.unsafe_get(get(t), i) +} + +/* +If asked for a length of samples shorter or equal the length of the distribution, +return this first n samples of this distribution. +Else, return n random samples of the distribution. +The former helps in cases where multiple distributions are correlated. +However, if n > length(t), then there's no clear right answer, so we just randomly +sample everything. +*/ +let sampleN = (t: t, n) => { + if n <= E.A.length(get(t)) { + E.A.slice(get(t), ~offset=0, ~len=n) + } else { + Belt.Array.makeBy(n, _ => sample(t)) + } +} + +let runMonteCarlo = (fn: (float, float) => float, t1: t, t2: t) => { + let samples = Belt.Array.zip(get(t1), get(t2))->E.A2.fmap(((a, b)) => fn(a, b)) + make(samples) +} diff --git a/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSet.res b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist_ToPointSet.res similarity index 85% rename from packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSet.res rename to packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist_ToPointSet.res index f8bce6f6..c8880f7a 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSet.res +++ b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist_ToPointSet.res @@ -1,8 +1,3 @@ -@genType -type t = array - -// TODO: Refactor to raise correct error when not enough samples - module Internals = { module Types = { type samplingStats = { @@ -145,25 +140,3 @@ let toPointSetDist = ( samplesParse } - -//Randomly get one sample from the distribution -let sample = (t: t): float => { - let i = E.Int.random(~min=0, ~max=E.A.length(t) - 1) - E.A.unsafe_get(t, i) -} - -/* -If asked for a length of samples shorter or equal the length of the distribution, -return this first n samples of this distribution. -Else, return n random samples of the distribution. -The former helps in cases where multiple distributions are correlated. -However, if n > length(t), then there's no clear right answer, so we just randomly -sample everything. -*/ -let sampleN = (t: t, n) => { - if n <= E.A.length(t) { - E.A.slice(t, ~offset=0, ~len=n) - } else { - Belt.Array.makeBy(n, _ => sample(t)) - } -} diff --git a/packages/squiggle-lang/src/rescript/OldInterpreter/ASTTypes.res b/packages/squiggle-lang/src/rescript/OldInterpreter/ASTTypes.res index 31217374..57b4577c 100644 --- a/packages/squiggle-lang/src/rescript/OldInterpreter/ASTTypes.res +++ b/packages/squiggle-lang/src/rescript/OldInterpreter/ASTTypes.res @@ -218,15 +218,15 @@ module SamplingDistribution = { algebraicOp, a, b, - ) + ) |> E.O.toResult("Could not get samples") + + let sampleSetDist = samples -> E.R.bind(SampleSetDist.make) let pointSetDist = - samples - |> E.O.fmap(r => - SampleSet.toPointSetDist(~samplingInputs=evaluationParams.samplingInputs, ~samples=r, ()) - ) - |> E.O.bind(_, r => r.pointSetDist) - |> E.O.toResult("No response") + sampleSetDist + -> E.R2.fmap(r => + SampleSetDist.toPointSetDist(~samplingInputs=evaluationParams.samplingInputs, ~samples=r, ())) + -> E.R.bind(r => r.pointSetDist |> E.O.toResult("combineShapesUsingSampling Error")) pointSetDist |> E.R.fmap(r => #Normalize(#RenderedDist(r))) }) } From fa3d874a4e263354c621b5fceb147c9b0e7aecd7 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Sat, 9 Apr 2022 20:21:02 -0400 Subject: [PATCH 34/41] Start of refactor for toPointSetDist --- .../Distributions/GenericDist/GenericDist.res | 30 ++++++++----------- .../SampleSetDist/SampleSetDist.res | 9 ++++-- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res index 90381fba..f87b3a22 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res @@ -64,22 +64,17 @@ let toPointSet = ( switch (t: t) { | PointSet(pointSet) => Ok(pointSet) | Symbolic(r) => Ok(SymbolicDist.T.toPointSetDist(~xSelection, xyPointLength, r)) - | SampleSet(r) => { - let response = SampleSetDist.toPointSetDist( - ~samples=r, - ~samplingInputs={ - sampleCount: sampleCount, - outputXYPoints: xyPointLength, - pointSetDistLength: xyPointLength, - kernelWidth: None, - }, - (), - ).pointSetDist - switch response { - | Some(r) => Ok(r) - | None => Error(Other("Converting sampleSet to pointSet failed")) - } - } + | SampleSet(r) => + SampleSetDist.toPointSetDist2( + ~samples=r, + ~samplingInputs={ + sampleCount: sampleCount, + outputXYPoints: xyPointLength, + pointSetDistLength: xyPointLength, + kernelWidth: None, + }, + (), + )->mapStringErrors } } @@ -170,8 +165,7 @@ module AlgebraicCombination = { ) => { let arithmeticOperation = Operation.Algebraic.toFn(arithmeticOperation) E.R.merge(toSampleSet(t1), toSampleSet(t2))->E.R.bind(((a, b)) => { - SampleSetDist.runMonteCarlo(arithmeticOperation, a, b) - ->mapStringErrors + SampleSetDist.map2(~fn=arithmeticOperation, ~t1=a, ~t2=b)->mapStringErrors }) } diff --git a/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist.res b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist.res index cea650f8..264b32ea 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist.res @@ -15,11 +15,15 @@ module T: { include T -// TODO: Refactor to raise correct error when not enough samples +let length = (t:t) => get(t) |> E.A.length; +// TODO: Refactor to raise correct error when not enough samples let toPointSetDist = (~samples: t, ~samplingInputs: SamplingInputs.samplingInputs, ()) => SampleSetDist_ToPointSet.toPointSetDist(~samples=get(samples), ~samplingInputs, ()) +let toPointSetDist2 = (~samples: t, ~samplingInputs: SamplingInputs.samplingInputs, ()) => + SampleSetDist_ToPointSet.toPointSetDist(~samples=get(samples), ~samplingInputs, ()).pointSetDist |> E.O.toResult("Failed to convert to PointSetDist") + //Randomly get one sample from the distribution let sample = (t: t): float => { let i = E.Int.random(~min=0, ~max=E.A.length(get(t)) - 1) @@ -42,7 +46,8 @@ let sampleN = (t: t, n) => { } } -let runMonteCarlo = (fn: (float, float) => float, t1: t, t2: t) => { +//TODO: Figure out what to do if distributions are different lengths. ``zip`` is kind of inelegant for this. +let map2 = (~fn: (float, float) => float, ~t1: t, ~t2: t) => { let samples = Belt.Array.zip(get(t1), get(t2))->E.A2.fmap(((a, b)) => fn(a, b)) make(samples) } From f17a842c526bf80ec56c96035478086aa89e0932 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Sat, 9 Apr 2022 20:27:03 -0400 Subject: [PATCH 35/41] Cleanup from previous refactor --- .../DistributionOperation_test.res | 9 --------- .../Distributions/GenericDist/GenericDist.res | 2 +- .../SampleSetDist/SampleSetDist.res | 18 +++++++++++------- .../src/rescript/OldInterpreter/ASTTypes.res | 7 +++---- 4 files changed, 15 insertions(+), 21 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Distributions/DistributionOperation_test.res b/packages/squiggle-lang/__tests__/Distributions/DistributionOperation_test.res index f206b31d..34a8dd6e 100644 --- a/packages/squiggle-lang/__tests__/Distributions/DistributionOperation_test.res +++ b/packages/squiggle-lang/__tests__/Distributions/DistributionOperation_test.res @@ -90,15 +90,6 @@ describe("toPointSet", () => { expect(result)->toBeSoCloseTo(5.0, ~digits=0) }) - test("on sample set distribution with under 4 points", () => { - let sampleSet = SampleSetDist.make([0.0, 1.0, 2.0, 3.0]) -> E.R.toExn; - let result = - run(FromDist(ToDist(ToPointSet), SampleSet(sampleSet)))->outputMap( - FromDist(ToFloat(#Mean)), - ) - expect(result)->toEqual(GenDistError(Other("Converting sampleSet to pointSet failed"))) - }) - test("on sample set", () => { let result = run(FromDist(ToDist(ToPointSet), normalDist5)) diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res index f87b3a22..a69d7f5d 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res @@ -65,7 +65,7 @@ let toPointSet = ( | PointSet(pointSet) => Ok(pointSet) | Symbolic(r) => Ok(SymbolicDist.T.toPointSetDist(~xSelection, xyPointLength, r)) | SampleSet(r) => - SampleSetDist.toPointSetDist2( + SampleSetDist.toPointSetDist( ~samples=r, ~samplingInputs={ sampleCount: sampleCount, diff --git a/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist.res b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist.res index 264b32ea..ccf1b775 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist.res @@ -15,14 +15,18 @@ module T: { include T -let length = (t:t) => get(t) |> E.A.length; +let length = (t: t) => get(t) |> E.A.length -// TODO: Refactor to raise correct error when not enough samples -let toPointSetDist = (~samples: t, ~samplingInputs: SamplingInputs.samplingInputs, ()) => - SampleSetDist_ToPointSet.toPointSetDist(~samples=get(samples), ~samplingInputs, ()) - -let toPointSetDist2 = (~samples: t, ~samplingInputs: SamplingInputs.samplingInputs, ()) => - SampleSetDist_ToPointSet.toPointSetDist(~samples=get(samples), ~samplingInputs, ()).pointSetDist |> E.O.toResult("Failed to convert to PointSetDist") +// TODO: Refactor to get error in the toPointSetDist function, instead of adding at very end. +let toPointSetDist = (~samples: t, ~samplingInputs: SamplingInputs.samplingInputs, ()): result< + PointSetTypes.pointSetDist, + string, +> => + SampleSetDist_ToPointSet.toPointSetDist( + ~samples=get(samples), + ~samplingInputs, + (), + ).pointSetDist |> E.O.toResult("Failed to convert to PointSetDist") //Randomly get one sample from the distribution let sample = (t: t): float => { diff --git a/packages/squiggle-lang/src/rescript/OldInterpreter/ASTTypes.res b/packages/squiggle-lang/src/rescript/OldInterpreter/ASTTypes.res index 57b4577c..3c14343a 100644 --- a/packages/squiggle-lang/src/rescript/OldInterpreter/ASTTypes.res +++ b/packages/squiggle-lang/src/rescript/OldInterpreter/ASTTypes.res @@ -222,11 +222,10 @@ module SamplingDistribution = { let sampleSetDist = samples -> E.R.bind(SampleSetDist.make) - let pointSetDist = + let pointSetDist = sampleSetDist - -> E.R2.fmap(r => - SampleSetDist.toPointSetDist(~samplingInputs=evaluationParams.samplingInputs, ~samples=r, ())) - -> E.R.bind(r => r.pointSetDist |> E.O.toResult("combineShapesUsingSampling Error")) + -> E.R.bind(r => + SampleSetDist.toPointSetDist(~samplingInputs=evaluationParams.samplingInputs, ~samples=r, ())); pointSetDist |> E.R.fmap(r => #Normalize(#RenderedDist(r))) }) } From db104694fd79d21288a388a9070f33380770c8be Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Sat, 9 Apr 2022 20:34:21 -0400 Subject: [PATCH 36/41] Cleaned up resultStringToResultError --- .../Distributions/GenericDist/GenericDist.res | 15 +++++++++------ .../GenericDist/GenericDist_Types.res | 9 +++++++++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res index a69d7f5d..772e83f7 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res @@ -5,15 +5,14 @@ type toPointSetFn = t => result type toSampleSetFn = t => result type scaleMultiplyFn = (t, float) => result type pointwiseAddFn = (t, t) => result -let mapStringErrors = n => n->E.R2.errMap(r => Error(GenericDist_Types.Other(r))) let sampleN = (t: t, n) => switch t { | PointSet(r) => Ok(PointSetDist.sampleNRendered(n, r)) | Symbolic(r) => Ok(SymbolicDist.T.sampleN(n, r)) | SampleSet(r) => Ok(SampleSetDist.sampleN(r, n)) } -let toSampleSetDist = (t: t, n) => sampleN(t, n)->E.R.bind(SampleSetDist.make)->mapStringErrors -let mapStringErrors = n => n->E.R2.errMap(r => Error(GenericDist_Types.Other(r))) +let toSampleSetDist = (t: t, n) => + sampleN(t, n)->E.R.bind(SampleSetDist.make)->GenericDist_Types.Error.resultStringToResultError let fromFloat = (f: float): t => Symbolic(SymbolicDist.Float.make(f)) @@ -74,7 +73,7 @@ let toPointSet = ( kernelWidth: None, }, (), - )->mapStringErrors + )->GenericDist_Types.Error.resultStringToResultError } } @@ -88,7 +87,7 @@ let toSparkline = (t: t, ~sampleCount: int, ~bucketCount: int=20, unit): result< t ->toPointSet(~xSelection=#Linear, ~xyPointLength=bucketCount * 3, ~sampleCount, ()) ->E.R.bind(r => - r->PointSetDist.toSparkline(bucketCount)->E.R2.errMap(r => Error(GenericDist_Types.Other(r))) + r->PointSetDist.toSparkline(bucketCount)->GenericDist_Types.Error.resultStringToResultError ) module Truncate = { @@ -165,7 +164,11 @@ module AlgebraicCombination = { ) => { let arithmeticOperation = Operation.Algebraic.toFn(arithmeticOperation) E.R.merge(toSampleSet(t1), toSampleSet(t2))->E.R.bind(((a, b)) => { - SampleSetDist.map2(~fn=arithmeticOperation, ~t1=a, ~t2=b)->mapStringErrors + SampleSetDist.map2( + ~fn=arithmeticOperation, + ~t1=a, + ~t2=b, + )->GenericDist_Types.Error.resultStringToResultError }) } diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res index c3c923a4..96e7d3f8 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res @@ -10,6 +10,15 @@ type error = | DistributionVerticalShiftIsInvalid | Other(string) +module Error = { + type t = error + + let fromString = (s: string): t => Other(s) + + let resultStringToResultError: result<'a, string> => result<'a, error> = n => + n->E.R2.errMap(r => r->fromString->Error) +} + module Operation = { type direction = | Algebraic From 9ad73fe69b84671d6ff5f417c442149796913dcb Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Sat, 9 Apr 2022 20:36:33 -0400 Subject: [PATCH 37/41] Power should be ** to be consistent --- packages/squiggle-lang/src/rescript/Utility/Operation.res | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/squiggle-lang/src/rescript/Utility/Operation.res b/packages/squiggle-lang/src/rescript/Utility/Operation.res index 5145955c..6fb3b24b 100644 --- a/packages/squiggle-lang/src/rescript/Utility/Operation.res +++ b/packages/squiggle-lang/src/rescript/Utility/Operation.res @@ -56,7 +56,7 @@ module Pointwise = { let toString = x => switch x { | #Add => "+" - | #Power => "^" + | #Power => "**" | #Multiply => "*" } From 4338f482ef37d9d5e0017c3a7e44c74e9c79723e Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Sat, 9 Apr 2022 21:24:44 -0400 Subject: [PATCH 38/41] Added genType to SampleSetDist to make pass tests, other minor fixes --- .../DistributionOperation.res | 14 ++++---- .../Distributions/GenericDist/GenericDist.res | 35 +++++++------------ .../GenericDist/GenericDist.resi | 3 +- .../SampleSetDist/SampleSetDist.res | 3 +- .../src/rescript/OldInterpreter/ASTTypes.res | 2 +- 5 files changed, 26 insertions(+), 31 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res index bb5f4f1a..71776f61 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res +++ b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res @@ -128,7 +128,10 @@ let rec run = (~env, functionCallInfo: functionCallInfo): outputType => { ->E.R2.fmap(r => Dist(r)) ->OutputLocal.fromResult | ToDist(ToSampleSet(n)) => - dist->GenericDist.toSampleSetDist(n)->E.R2.fmap(r => Dist(SampleSet(r)))->OutputLocal.fromResult + dist + ->GenericDist.toSampleSetDist(n) + ->E.R2.fmap(r => Dist(SampleSet(r))) + ->OutputLocal.fromResult | ToDist(ToPointSet) => dist ->GenericDist.toPointSet(~xyPointLength, ~sampleCount, ()) @@ -204,7 +207,8 @@ module Constructors = { C.truncate(dist, leftCutoff, rightCutoff)->run(~env)->toDistR let inspect = (~env, dist) => C.inspect(dist)->run(~env)->toDistR let toString = (~env, dist) => C.toString(dist)->run(~env)->toStringR - let toSparkline = (~env, dist, bucketCount) => C.toSparkline(dist, bucketCount)->run(~env)->toStringR + let toSparkline = (~env, dist, bucketCount) => + C.toSparkline(dist, bucketCount)->run(~env)->toStringR let algebraicAdd = (~env, dist1, dist2) => C.algebraicAdd(dist1, dist2)->run(~env)->toDistR let algebraicMultiply = (~env, dist1, dist2) => C.algebraicMultiply(dist1, dist2)->run(~env)->toDistR @@ -213,8 +217,7 @@ module Constructors = { C.algebraicSubtract(dist1, dist2)->run(~env)->toDistR let algebraicLogarithm = (~env, dist1, dist2) => C.algebraicLogarithm(dist1, dist2)->run(~env)->toDistR - let algebraicPower = (~env, dist1, dist2) => - C.algebraicPower(dist1, dist2)->run(~env)->toDistR + let algebraicPower = (~env, dist1, dist2) => C.algebraicPower(dist1, dist2)->run(~env)->toDistR let pointwiseAdd = (~env, dist1, dist2) => C.pointwiseAdd(dist1, dist2)->run(~env)->toDistR let pointwiseMultiply = (~env, dist1, dist2) => C.pointwiseMultiply(dist1, dist2)->run(~env)->toDistR @@ -223,6 +226,5 @@ module Constructors = { C.pointwiseSubtract(dist1, dist2)->run(~env)->toDistR let pointwiseLogarithm = (~env, dist1, dist2) => C.pointwiseLogarithm(dist1, dist2)->run(~env)->toDistR - let pointwisePower = (~env, dist1, dist2) => - C.pointwisePower(dist1, dist2)->run(~env)->toDistR + let pointwisePower = (~env, dist1, dist2) => C.pointwisePower(dist1, dist2)->run(~env)->toDistR } diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res index 772e83f7..b14ea27f 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res @@ -5,14 +5,16 @@ type toPointSetFn = t => result type toSampleSetFn = t => result type scaleMultiplyFn = (t, float) => result type pointwiseAddFn = (t, t) => result + let sampleN = (t: t, n) => switch t { - | PointSet(r) => Ok(PointSetDist.sampleNRendered(n, r)) - | Symbolic(r) => Ok(SymbolicDist.T.sampleN(n, r)) - | SampleSet(r) => Ok(SampleSetDist.sampleN(r, n)) + | PointSet(r) => PointSetDist.sampleNRendered(n, r) + | Symbolic(r) => SymbolicDist.T.sampleN(n, r) + | SampleSet(r) => SampleSetDist.sampleN(r, n) } + let toSampleSetDist = (t: t, n) => - sampleN(t, n)->E.R.bind(SampleSetDist.make)->GenericDist_Types.Error.resultStringToResultError + SampleSetDist.make(sampleN(t, n))->GenericDist_Types.Error.resultStringToResultError let fromFloat = (f: float): t => Symbolic(SymbolicDist.Float.make(f)) @@ -72,7 +74,6 @@ let toPointSet = ( pointSetDistLength: xyPointLength, kernelWidth: None, }, - (), )->GenericDist_Types.Error.resultStringToResultError } } @@ -162,14 +163,12 @@ module AlgebraicCombination = { t1: t, t2: t, ) => { - let arithmeticOperation = Operation.Algebraic.toFn(arithmeticOperation) - E.R.merge(toSampleSet(t1), toSampleSet(t2))->E.R.bind(((a, b)) => { - SampleSetDist.map2( - ~fn=arithmeticOperation, - ~t1=a, - ~t2=b, - )->GenericDist_Types.Error.resultStringToResultError + let fn = Operation.Algebraic.toFn(arithmeticOperation) + E.R.merge(toSampleSet(t1), toSampleSet(t2)) + ->E.R.bind(((t1, t2)) => { + SampleSetDist.map2(~fn, ~t1, ~t2)->GenericDist_Types.Error.resultStringToResultError }) + ->E.R2.fmap(r => GenericDist_Types.SampleSet(r)) } //I'm (Ozzie) really just guessing here, very little idea what's best @@ -200,15 +199,7 @@ module AlgebraicCombination = { | Some(Error(e)) => Error(Other(e)) | None => switch chooseConvolutionOrMonteCarlo(t1, t2) { - | #CalculateWithMonteCarlo => { - let sampleSetDist: result = runMonteCarlo( - toSampleSetFn, - arithmeticOperation, - t1, - t2, - ) - sampleSetDist->E.R2.fmap(r => GenericDist_Types.SampleSet(r)) - } + | #CalculateWithMonteCarlo => runMonteCarlo(toSampleSetFn, arithmeticOperation, t1, t2) | #CalculateWithConvolution => runConvolution( toPointSetFn, @@ -274,7 +265,7 @@ let mixture = ( ~pointwiseAddFn: pointwiseAddFn, ) => { if E.A.length(values) == 0 { - Error(GenericDist_Types.Other("mixture must have at least 1 element")) + Error(GenericDist_Types.Other("Mixture error: mixture must have at least 1 element")) } else { let totalWeight = values->E.A2.fmap(E.Tuple2.second)->E.A.Floats.sum let properlyWeightedValues = diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi index b65489e3..4565ec14 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi @@ -5,7 +5,8 @@ type toSampleSetFn = t => result type scaleMultiplyFn = (t, float) => result type pointwiseAddFn = (t, t) => result -let sampleN: (t, int) => result, error> +let sampleN: (t, int) => array + let toSampleSetDist: (t, int) => Belt.Result.t let fromFloat: float => t diff --git a/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist.res b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist.res index ccf1b775..7a63332f 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist.res @@ -1,4 +1,5 @@ module T: { + @genType type t let make: array => result let get: t => array @@ -18,7 +19,7 @@ include T let length = (t: t) => get(t) |> E.A.length // TODO: Refactor to get error in the toPointSetDist function, instead of adding at very end. -let toPointSetDist = (~samples: t, ~samplingInputs: SamplingInputs.samplingInputs, ()): result< +let toPointSetDist = (~samples: t, ~samplingInputs: SamplingInputs.samplingInputs): result< PointSetTypes.pointSetDist, string, > => diff --git a/packages/squiggle-lang/src/rescript/OldInterpreter/ASTTypes.res b/packages/squiggle-lang/src/rescript/OldInterpreter/ASTTypes.res index 3c14343a..17477f8f 100644 --- a/packages/squiggle-lang/src/rescript/OldInterpreter/ASTTypes.res +++ b/packages/squiggle-lang/src/rescript/OldInterpreter/ASTTypes.res @@ -225,7 +225,7 @@ module SamplingDistribution = { let pointSetDist = sampleSetDist -> E.R.bind(r => - SampleSetDist.toPointSetDist(~samplingInputs=evaluationParams.samplingInputs, ~samples=r, ())); + SampleSetDist.toPointSetDist(~samplingInputs=evaluationParams.samplingInputs, ~samples=r)); pointSetDist |> E.R.fmap(r => #Normalize(#RenderedDist(r))) }) } From 5b0efbb3a85b796acea70f091d74c49d0c725bce Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Sat, 9 Apr 2022 21:31:34 -0400 Subject: [PATCH 39/41] Bandwidth -> SampleSetDist_Bandwidth --- .../squiggle-lang/__tests__/Bandwidth_test.res | 4 ++-- .../Distributions/SampleSetDist/SampleSetDist.res | 14 +++++++++++--- .../{Bandwidth.res => SampleSetDist_Bandwidth.res} | 2 +- .../SampleSetDist/SampleSetDist_ToPointSet.res | 4 ++-- 4 files changed, 16 insertions(+), 8 deletions(-) rename packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/{Bandwidth.res => SampleSetDist_Bandwidth.res} (94%) diff --git a/packages/squiggle-lang/__tests__/Bandwidth_test.res b/packages/squiggle-lang/__tests__/Bandwidth_test.res index d37e5bb8..4e5c630a 100644 --- a/packages/squiggle-lang/__tests__/Bandwidth_test.res +++ b/packages/squiggle-lang/__tests__/Bandwidth_test.res @@ -4,10 +4,10 @@ open Expect describe("Bandwidth", () => { test("nrd0()", () => { let data = [1., 4., 3., 2.] - expect(Bandwidth.nrd0(data)) -> toEqual(0.7625801874014622) + expect(SampleSetDist_Bandwidth.nrd0(data)) -> toEqual(0.7625801874014622) }) test("nrd()", () => { let data = [1., 4., 3., 2.] - expect(Bandwidth.nrd(data)) -> toEqual(0.8981499984950554) + expect(SampleSetDist_Bandwidth.nrd(data)) -> toEqual(0.8981499984950554) }) }) diff --git a/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist.res b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist.res index 7a63332f..f8dfd84a 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist.res @@ -1,3 +1,8 @@ +/* +This is used as a smart constructor. The only way to create a SampleSetDist.t is to call +this constructor. +https://stackoverflow.com/questions/66909578/how-to-make-a-type-constructor-private-in-rescript-except-in-current-module +*/ module T: { @genType type t @@ -16,9 +21,12 @@ module T: { include T -let length = (t: t) => get(t) |> E.A.length +let length = (t: t) => get(t)->E.A.length -// TODO: Refactor to get error in the toPointSetDist function, instead of adding at very end. +/* +TODO: Refactor to get a more precise estimate. Also, this code is just fairly messy, could use +some refactoring. +*/ let toPointSetDist = (~samples: t, ~samplingInputs: SamplingInputs.samplingInputs): result< PointSetTypes.pointSetDist, string, @@ -27,7 +35,7 @@ let toPointSetDist = (~samples: t, ~samplingInputs: SamplingInputs.samplingInput ~samples=get(samples), ~samplingInputs, (), - ).pointSetDist |> E.O.toResult("Failed to convert to PointSetDist") + ).pointSetDist->E.O2.toResult("Failed to convert to PointSetDist") //Randomly get one sample from the distribution let sample = (t: t): float => { diff --git a/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/Bandwidth.res b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist_Bandwidth.res similarity index 94% rename from packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/Bandwidth.res rename to packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist_Bandwidth.res index 6650b862..aef659d1 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/Bandwidth.res +++ b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist_Bandwidth.res @@ -1,4 +1,4 @@ -//The math here was taken from https://github.com/jasondavies/science.js/blob/master/src/stats/bandwidth.js +//The math here was taken from https://github.com/jasondavies/science.js/blob/master/src/stats/SampleSetDist_Bandwidth.js let len = x => E.A.length(x) |> float_of_int diff --git a/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist_ToPointSet.res b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist_ToPointSet.res index c8880f7a..59b4fa46 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist_ToPointSet.res +++ b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist_ToPointSet.res @@ -70,7 +70,7 @@ module Internals = { let formatUnitWidth = w => Jstat.max([w, 1.0]) |> int_of_float let suggestedUnitWidth = (samples, outputXYPoints) => { - let suggestedXWidth = Bandwidth.nrd0(samples) + let suggestedXWidth = SampleSetDist_Bandwidth.nrd0(samples) xWidthToUnitWidth(samples, outputXYPoints, suggestedXWidth) } @@ -97,7 +97,7 @@ let toPointSetDist = ( let pdf = continuousPart |> E.A.length > 5 ? { - let _suggestedXWidth = Bandwidth.nrd0(continuousPart) + let _suggestedXWidth = SampleSetDist_Bandwidth.nrd0(continuousPart) // todo: This does some recalculating from the last step. let _suggestedUnitWidth = Internals.T.suggestedUnitWidth( continuousPart, From ec5dc4667f5dc85fadfa30c80d6cc5052312a034 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Sat, 9 Apr 2022 21:39:10 -0400 Subject: [PATCH 40/41] Samples_test -> SampleSetDist_test --- .../Distributions/{Samples_test.res => SampleSetDist_test.res} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename packages/squiggle-lang/__tests__/Distributions/{Samples_test.res => SampleSetDist_test.res} (100%) diff --git a/packages/squiggle-lang/__tests__/Distributions/Samples_test.res b/packages/squiggle-lang/__tests__/Distributions/SampleSetDist_test.res similarity index 100% rename from packages/squiggle-lang/__tests__/Distributions/Samples_test.res rename to packages/squiggle-lang/__tests__/Distributions/SampleSetDist_test.res From c94a70b93ac98f9ad05245c51d69b8d160aa2ea0 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Sat, 9 Apr 2022 21:56:05 -0400 Subject: [PATCH 41/41] Fixed tests --- packages/squiggle-lang/__tests__/JS__Test.ts | 3 ++- packages/squiggle-lang/src/js/index.ts | 5 +++++ .../rescript/Distributions/SampleSetDist/SampleSetDist.res | 4 +++- packages/squiggle-lang/src/rescript/TypescriptInterface.res | 3 +++ 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/squiggle-lang/__tests__/JS__Test.ts b/packages/squiggle-lang/__tests__/JS__Test.ts index ba2f91f4..8e5961a3 100644 --- a/packages/squiggle-lang/__tests__/JS__Test.ts +++ b/packages/squiggle-lang/__tests__/JS__Test.ts @@ -1,4 +1,4 @@ -import { run, GenericDist, resultMap } from "../src/js/index"; +import { run, GenericDist, resultMap, makeSampleSetDist } from "../src/js/index"; let testRun = (x: string) => { let result = run(x); @@ -41,6 +41,7 @@ describe("Multimodal too many weights error", () => { describe("GenericDist", () => { //It's important that sampleCount is less than 9. If it's more, than that will create randomness + //Also, note, the value should be created using makeSampleSetDist() later on. let env = { sampleCount: 8, xyPointLength: 100 }; let dist = new GenericDist( { tag: "SampleSet", value: [3, 4, 5, 6, 6, 7, 10, 15, 30] }, diff --git a/packages/squiggle-lang/src/js/index.ts b/packages/squiggle-lang/src/js/index.ts index 1f67e369..4892c2f3 100644 --- a/packages/squiggle-lang/src/js/index.ts +++ b/packages/squiggle-lang/src/js/index.ts @@ -14,6 +14,7 @@ import { resultFloat, resultString, } from "../rescript/TypescriptInterface.gen"; +export {makeSampleSetDist} from "../rescript/TypescriptInterface.gen"; import { Constructors_mean, Constructors_sample, @@ -79,6 +80,10 @@ export function resultMap(r: result, mapFn: any): result { } } +export function resultExn(r: result): any { + r.value +} + export class GenericDist { t: genericDist; env: env; diff --git a/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist.res b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist.res index f8dfd84a..fcd4055d 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist.res @@ -4,8 +4,10 @@ this constructor. https://stackoverflow.com/questions/66909578/how-to-make-a-type-constructor-private-in-rescript-except-in-current-module */ module T: { + //This really should be hidden (remove the array). The reason it isn't is to act as an escape hatch in JS__Test.ts. + //When we get a good functional library in TS, we could refactor that out. @genType - type t + type t = array let make: array => result let get: t => array } = { diff --git a/packages/squiggle-lang/src/rescript/TypescriptInterface.res b/packages/squiggle-lang/src/rescript/TypescriptInterface.res index fb30ea24..6fe6f3d4 100644 --- a/packages/squiggle-lang/src/rescript/TypescriptInterface.res +++ b/packages/squiggle-lang/src/rescript/TypescriptInterface.res @@ -22,3 +22,6 @@ type resultDist = result type resultFloat = result @genType type resultString = result + +@genType +let makeSampleSetDist = SampleSetDist.make \ No newline at end of file