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__/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__/GenericDist/GenericOperation__Test.res b/packages/squiggle-lang/__tests__/Distributions/DistributionOperation_test.res similarity index 55% rename from packages/squiggle-lang/__tests__/GenericDist/GenericOperation__Test.res rename to packages/squiggle-lang/__tests__/Distributions/DistributionOperation_test.res index dc456865..bfe630ae 100644 --- a/packages/squiggle-lang/__tests__/GenericDist/GenericOperation__Test.res +++ b/packages/squiggle-lang/__tests__/Distributions/DistributionOperation_test.res @@ -6,9 +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 mkNormal = (mean, stdev) => GenericDist_Types.Symbolic(#Normal({mean: mean, stdev: stdev})) +let normalDist5: GenericDist_Types.genericDist = mkNormal(5.0, 2.0) let uniformDist: GenericDist_Types.genericDist = Symbolic(#Uniform({low: 9.0, high: 10.0})) let {toFloat, toDist, toString, toError} = module(DistributionOperation.Output) @@ -20,31 +19,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("toPointSet", () => { test("on symbolic normal distribution", () => { let result = @@ -52,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", () => { @@ -63,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)))) @@ -71,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/Mixture_test.res b/packages/squiggle-lang/__tests__/Distributions/Mixture_test.res new file mode 100644 index 00000000..2ab1de08 --- /dev/null +++ b/packages/squiggle-lang/__tests__/Distributions/Mixture_test.res @@ -0,0 +1,70 @@ +open Jest +open Expect +open TestHelpers + +// 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})) +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 + let (mean1, mean2) = tup + let meanValue = { + run(Mixture([(mkNormal(mean1, 9e-1), 0.5), (mkNormal(mean2, 9e-1), 0.5)])) + -> outputMap(FromDist(ToFloat(#Mean))) + } + 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 ((alpha, beta), rate) = tup + let betaWeight = 0.25 + let exponentialWeight = 0.75 + let meanValue = { + run(Mixture( + [ + (mkBeta(alpha, beta), betaWeight), + (mkExponential(rate), exponentialWeight) + ] + )) -> outputMap(FromDist(ToFloat(#Mean))) + } + let betaMean = 1.0 /. (1.0 +. beta /. alpha) + let exponentialMean = 1.0 /. rate + meanValue + -> unpackFloat + -> expect + -> toBeSoCloseTo( + betaWeight *. betaMean +. exponentialWeight *. exponentialMean, + ~digits=-1 + ) + } + ) + testAll( + "weighted mean of lognormal and uniform", + // 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 ((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))) + } + let uniformMean = (low +. high) /. 2.0 + let lognormalMean = mu +. sigma ** 2.0 /. 2.0 + meanValue + -> unpackFloat + -> expect + -> 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 new file mode 100644 index 00000000..db80f9f7 --- /dev/null +++ b/packages/squiggle-lang/__tests__/Distributions/Samples_test.res @@ -0,0 +1,41 @@ +open Jest +open TestHelpers + +describe("Continuous and discrete splits", () => { + makeTest( + "splits (1)", + SampleSet.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([ + 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 (_, discrete1) = SampleSet.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( + makeDuplicatedArray(500), + ) + let toArr2 = discrete2 |> E.FloatFloatMap.toArray + makeTest("splitMedium at count=500", toArr2 |> Belt.Array.length, 500) +}) + 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..59ab2a8b --- /dev/null +++ b/packages/squiggle-lang/__tests__/Distributions/Symbolic_test.res @@ -0,0 +1,161 @@ +open Jest +open Expect +open TestHelpers + +// 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})) + +describe("(Symbolic) normalize", () => { + 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(normalValue) + }) +}) + +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 + -> expect + -> 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 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 meanValue = run(FromDist(ToFloat(#Mean), GenericDist_Types.Symbolic(#Cauchy({local: 1.0, scale: 1.0})))) + meanValue + -> unpackFloat + -> expect + -> toBeCloseTo(2.01868297874546) + //-> toBe(GenDistError(Other("Cauchy distributions may have no mean value."))) + }) + + 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 meanValue = run(FromDist( + ToFloat(#Mean), + GenericDist_Types.Symbolic(#Triangular({low: low, medium: medium, high: high})) + )) + meanValue + -> unpackFloat + -> expect + -> 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 meanValue = run(FromDist( + ToFloat(#Mean), + GenericDist_Types.Symbolic(#Beta({alpha: alpha, beta: beta})) + )) + meanValue + -> unpackFloat + -> expect + -> 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 meanValue = run(FromDist( + ToFloat(#Mean), + GenericDist_Types.Symbolic(#Beta({alpha: 0.0, beta: 0.0})) + )) + meanValue + -> unpackFloat + -> expect + -> ExpectJs.toBeFalsy + }) + + 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 meanValue = run(FromDist( + ToFloat(#Mean), + GenericDist_Types.Symbolic(#Lognormal({mu: mu, sigma: sigma})) + )) + meanValue + -> unpackFloat + -> expect + -> toBeCloseTo(Js.Math.exp(mu +. sigma ** 2.0 /. 2.0 )) // https://brilliant.org/wiki/log-normal-distribution/ + }) + + testAll("of uniform distributions", list{(1e-5, 12.345), (-1e4, 1e4), (-1e16, -1e2), (5.3e3, 9e9)}, tup => { + let (low, high) = tup + let meanValue = run(FromDist( + ToFloat(#Mean), + GenericDist_Types.Symbolic(#Uniform({low: low, high: high})) + )) + meanValue + -> unpackFloat + -> expect + -> toBeCloseTo((low +. high) /. 2.0) // https://en.wikipedia.org/wiki/Continuous_uniform_distribution#Moments + }) + + test("of a float", () => { + let meanValue = run(FromDist( + ToFloat(#Mean), + GenericDist_Types.Symbolic(#Float(7.7)) + )) + meanValue -> unpackFloat -> expect -> toBeCloseTo(7.7) + }) +}) + +describe("Normal distribution with sparklines", () => { + + let parameterWiseAdditionPdf = (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,] + + test("mean=5 pdf", () => { + let pdfNormalDistAtMean5 = x => SymbolicDist.Normal.pdf(x, normalDistAtMean5) + let sparklineMean5 = fnImage(pdfNormalDistAtMean5, range20Float) + Sparklines.create(sparklineMean5, ()) + -> expect + -> toEqual(`▁▂▃▅███▅▃▂▁▁▁▁▁▁▁▁▁▁▁`) + }) + + test("parameter-wise addition of two normal distributions", () => { + let sparklineMean15 = normalDistAtMean5 -> parameterWiseAdditionPdf(normalDistAtMean10) -> fnImage(range20Float) + Sparklines.create(sparklineMean15, ()) + -> expect + -> toEqual(`▁▁▁▁▁▁▁▁▁▁▂▃▅▇███▇▅▃▂`) + }) + + test("mean=10 cdf", () => { + let cdfNormalDistAtMean10 = x => SymbolicDist.Normal.cdf(x, normalDistAtMean10) + let sparklineMean10 = fnImage(cdfNormalDistAtMean10, range20Float) + Sparklines.create(sparklineMean10, ()) + -> expect + -> toEqual(`▁▁▁▁▁▁▁▁▂▃▅▆▇████████`) + }) +}) 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__/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/__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, ()), `▁▁▁▁▁▁▁▁▁▁▂▃▅▇███▇▅▃▂`) -}) 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/__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 diff --git a/packages/squiggle-lang/bsconfig.json b/packages/squiggle-lang/bsconfig.json index 4f38e124..e936eb82 100644 --- a/packages/squiggle-lang/bsconfig.json +++ b/packages/squiggle-lang/bsconfig.json @@ -47,7 +47,7 @@ [ "../../node_modules/bisect_ppx/ppx", "--exclude-files", - ".*_Test\\.res$$" + ".*_test\\.res$$" ] ] } 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" + ], }; 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": [ 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 = { 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 ce5accca..511b327f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8434,6 +8434,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" @@ -13566,6 +13573,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" @@ -14754,6 +14766,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"