From 24fe66c9d3d9b18c648cd95c711c597b5999fc41 Mon Sep 17 00:00:00 2001 From: Quinn Dougherty Date: Wed, 13 Apr 2022 19:17:49 -0400 Subject: [PATCH 1/4] 6/6 tasks done --- .../Distributions/Invariants/Means_test.res | 162 +++++++++--------- .../squiggle-lang/__tests__/TestHelpers.res | 10 ++ 2 files changed, 89 insertions(+), 83 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Distributions/Invariants/Means_test.res b/packages/squiggle-lang/__tests__/Distributions/Invariants/Means_test.res index 51f9d1c1..01f52b7c 100644 --- a/packages/squiggle-lang/__tests__/Distributions/Invariants/Means_test.res +++ b/packages/squiggle-lang/__tests__/Distributions/Invariants/Means_test.res @@ -1,15 +1,65 @@ /* This is the most basic file in our invariants family of tests. -See document in https://github.com/quantified-uncertainty/squiggle/pull/238 for details +Validate that the addition of means equals the mean of the addition, similar for subtraction and multiplication. -Note: digits parameter should be higher than -4. +Details in https://deploy-preview-251--squiggle-documentation.netlify.app/docs/internal/invariants/ + +Note: epsilon of 1e3 means the invariants are, in general, not being satisfied. */ open Jest open Expect open TestHelpers +module Internals = { + let epsilon = 1e3 + + let mean = GenericDist_Types.Constructors.UsingDists.mean + + let expectImpossiblePath: string => assertion = algebraicOp => + `${algebraicOp} has`->expect->toEqual("failed") + + let distributions = list{ + normalMake(0.0, 1e0), + betaMake(2e0, 4e0), + exponentialMake(1.234e0), + uniformMake(7e0, 1e1), + // cauchyMake(1e0, 1e0), + lognormalMake(1e0, 1e0), + triangularMake(1e0, 1e1, 5e1), + Ok(floatMake(1e1)), + } + let pairsOfDifferentDistributions = E.L.combinations2(distributions) + + let runMean: DistributionTypes.genericDist => float = dist => { + dist->mean->run->toFloat->E.O2.toExn("Shouldn't see this because we trust testcase input") + } + + let testOperationMean = ( + distOp: (DistributionTypes.genericDist, DistributionTypes.genericDist) => result, + description: string, + floatOp: (float, float) => float, + dist1': SymbolicDistTypes.symbolicDist, + dist2': SymbolicDistTypes.symbolicDist, + ~epsilon: float + ) => { + let dist1 = dist1'->DistributionTypes.Symbolic // ->DistributionTypes.Other + let dist2 = dist2'->DistributionTypes.Symbolic // ->DistributionTypes.Other + let received = + distOp(dist1, dist2) + ->E.R2.fmap(mean) + ->E.R2.fmap(run) + ->E.R2.fmap(toFloat) + ->E.R.toExn + let expected = floatOp(runMean(dist1), runMean(dist2)) + switch received { + | None => expectImpossiblePath(description) + | Some(x) => expectErrorToBeBounded(x, expected, ~epsilon=epsilon) + } + } +} + let { algebraicAdd, algebraicMultiply, @@ -26,115 +76,61 @@ let algebraicSubtract = algebraicSubtract(~env) let algebraicLogarithm = algebraicLogarithm(~env) let algebraicPower = algebraicPower(~env) -describe("Mean", () => { - let digits = -4 +let {testOperationMean, distributions, pairsOfDifferentDistributions, epsilon} = module(Internals) - let mean = GenericDist_Types.Constructors.UsingDists.mean +describe("Means invariant", () => { - let runMean: result => float = distR => { - distR - ->E.R2.fmap(mean) - ->E.R2.fmap(run) - ->E.R2.fmap(toFloat) - ->E.R.toExn - ->E.O2.toExn("Shouldn't see this because we trust testcase input") - } - - let impossiblePath: string => assertion = algebraicOp => - `${algebraicOp} has`->expect->toEqual("failed") - - let distributions = list{ - normalMake(0.0, 1e0), - betaMake(2e0, 4e0), - exponentialMake(1.234e0), - uniformMake(7e0, 1e1), - // cauchyMake(1e0, 1e0), - lognormalMake(1e0, 1e0), - triangularMake(1e0, 1e1, 5e1), - Ok(floatMake(1e1)), - } - let combinations = E.L.combinations2(distributions) - let zipDistsDists = E.L.zip(distributions, distributions) - - let testOperationMean = ( - distOp: (DistributionTypes.genericDist, DistributionTypes.genericDist) => result, - description: string, - floatOp: (float, float) => float, - dist1': result, - dist2': result - ) => { - let dist1 = dist1'->E.R2.fmap(x=>DistributionTypes.Symbolic(x))->E.R2.fmap2(s=>DistributionTypes.Other(s)) - let dist2 = dist2'->E.R2.fmap(x=>DistributionTypes.Symbolic(x))->E.R2.fmap2(s=>DistributionTypes.Other(s)) - let received = - E.R.liftJoin2(distOp, dist1, dist2) - ->E.R2.fmap(mean) - ->E.R2.fmap(run) - ->E.R2.fmap(toFloat) - let expected = floatOp(runMean(dist1), runMean(dist2)) - switch received { - | Error(err) => impossiblePath(description) - | Ok(x) => - switch x { - | None => impossiblePath(description) - | Some(x) => x->expect->toBeSoCloseTo(expected, ~digits) - } - } - } - - describe("addition", () => { - let testAdditionMean = testOperationMean(algebraicAdd, "algebraicAdd", \"+.") - - testAll("homogeneous addition", zipDistsDists, dists => { - let (dist1, dist2) = dists - testAdditionMean(dist1, dist2) + describe("for addition", () => { + let testAdditionMean = testOperationMean(algebraicAdd, "algebraicAdd", \"+.", ~epsilon=epsilon) + + testAll("of two of the same distribution", distributions, dist => { + E.R.liftM2(testAdditionMean, dist, dist) -> E.R.toExn }) - testAll("heterogeneous addition (1)", combinations, dists => { + testAll("of two different distributions", pairsOfDifferentDistributions, dists => { let (dist1, dist2) = dists - testAdditionMean(dist1, dist2) + E.R.liftM2(testAdditionMean, dist1, dist2) -> E.R.toExn }) - testAll("heterogeneous addition (commuted of 1 (or; 2))", combinations, dists => { + testAll("of two difference distributions", pairsOfDifferentDistributions, dists => { let (dist1, dist2) = dists - testAdditionMean(dist2, dist1) + E.R.liftM2(testAdditionMean, dist2, dist1) -> E.R.toExn }) }) - describe("subtraction", () => { - let testSubtractionMean = testOperationMean(algebraicSubtract, "algebraicSubtract", \"-.") + describe("for subtraction", () => { + let testSubtractionMean = testOperationMean(algebraicSubtract, "algebraicSubtract", \"-.", ~epsilon=epsilon) - testAll("homogeneous subtraction", zipDistsDists, dists => { - let (dist1, dist2) = dists - testSubtractionMean(dist1, dist2) + testAll("of two of the same distribution", distributions, dist => { + E.R.liftM2(testSubtractionMean, dist, dist) -> E.R.toExn }) - testAll("heterogeneous subtraction (1)", combinations, dists => { + testAll("of two different distributions", pairsOfDifferentDistributions, dists => { let (dist1, dist2) = dists - testSubtractionMean(dist1, dist2) + E.R.liftM2(testSubtractionMean, dist1, dist2) -> E.R.toExn }) - testAll("heterogeneous subtraction (commuted of 1 (or; 2))", combinations, dists => { + testAll("of two different distributions", pairsOfDifferentDistributions, dists => { let (dist1, dist2) = dists - testSubtractionMean(dist2, dist1) + E.R.liftM2(testSubtractionMean, dist2, dist1) -> E.R.toExn }) }) - describe("multiplication", () => { - let testMultiplicationMean = testOperationMean(algebraicMultiply, "algebraicMultiply", \"*.") + describe("for multiplication", () => { + let testMultiplicationMean = testOperationMean(algebraicMultiply, "algebraicMultiply", \"*.", ~epsilon=epsilon) - testAll("homogeneous subtraction", zipDistsDists, dists => { - let (dist1, dist2) = dists - testMultiplicationMean(dist1, dist2) + testAll("of two of the same distribution", distributions, dist => { + E.R.liftM2(testMultiplicationMean, dist, dist) -> E.R.toExn }) - testAll("heterogeneoous subtraction (1)", combinations, dists => { + testAll("of two different distributions", pairsOfDifferentDistributions, dists => { let (dist1, dist2) = dists - testMultiplicationMean(dist1, dist2) + E.R.liftM2(testMultiplicationMean, dist1, dist2) -> E.R.toExn }) - testAll("heterogeneoous subtraction (commuted of 1 (or; 2))", combinations, dists => { + testAll("of two different distributions", pairsOfDifferentDistributions, dists => { let (dist1, dist2) = dists - testMultiplicationMean(dist2, dist1) + E.R.liftM2(testMultiplicationMean, dist2, dist1) -> E.R.toExn }) }) }) diff --git a/packages/squiggle-lang/__tests__/TestHelpers.res b/packages/squiggle-lang/__tests__/TestHelpers.res index 4967f75c..bff21805 100644 --- a/packages/squiggle-lang/__tests__/TestHelpers.res +++ b/packages/squiggle-lang/__tests__/TestHelpers.res @@ -1,6 +1,16 @@ open Jest open Expect +let expectErrorToBeBounded = (received, expected, ~epsilon) => { + let distance = Js.Math.abs_float(received -. expected) + let error = if expected < epsilon ** 2.5 { + distance /. epsilon + } else { + distance /. Js.Math.abs_float(expected) + } + error -> expect -> toBeLessThan(epsilon) +} + let makeTest = (~only=false, str, item1, item2) => only ? Only.test(str, () => expect(item1)->toEqual(item2)) From b0ff2c19f5e810847bb205541dcce4541a77d6dd Mon Sep 17 00:00:00 2001 From: Quinn Dougherty Date: Wed, 13 Apr 2022 19:18:08 -0400 Subject: [PATCH 2/4] `yarn format` --- .../Distributions/Invariants/Means_test.res | 68 +++++++++++-------- .../squiggle-lang/__tests__/TestHelpers.res | 2 +- .../ReducerInterface_GenericDistribution.res | 3 +- .../squiggle-lang/src/rescript/Utility/E.res | 4 +- 4 files changed, 43 insertions(+), 34 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Distributions/Invariants/Means_test.res b/packages/squiggle-lang/__tests__/Distributions/Invariants/Means_test.res index 01f52b7c..a499565b 100644 --- a/packages/squiggle-lang/__tests__/Distributions/Invariants/Means_test.res +++ b/packages/squiggle-lang/__tests__/Distributions/Invariants/Means_test.res @@ -16,7 +16,7 @@ module Internals = { let epsilon = 1e3 let mean = GenericDist_Types.Constructors.UsingDists.mean - + let expectImpossiblePath: string => assertion = algebraicOp => `${algebraicOp} has`->expect->toEqual("failed") @@ -37,25 +37,24 @@ module Internals = { } let testOperationMean = ( - distOp: (DistributionTypes.genericDist, DistributionTypes.genericDist) => result, - description: string, - floatOp: (float, float) => float, - dist1': SymbolicDistTypes.symbolicDist, - dist2': SymbolicDistTypes.symbolicDist, - ~epsilon: float - ) => { - let dist1 = dist1'->DistributionTypes.Symbolic // ->DistributionTypes.Other - let dist2 = dist2'->DistributionTypes.Symbolic // ->DistributionTypes.Other + distOp: ( + DistributionTypes.genericDist, + DistributionTypes.genericDist, + ) => result, + description: string, + floatOp: (float, float) => float, + dist1': SymbolicDistTypes.symbolicDist, + dist2': SymbolicDistTypes.symbolicDist, + ~epsilon: float, + ) => { + let dist1 = dist1'->DistributionTypes.Symbolic // ->DistributionTypes.Other + let dist2 = dist2'->DistributionTypes.Symbolic // ->DistributionTypes.Other let received = - distOp(dist1, dist2) - ->E.R2.fmap(mean) - ->E.R2.fmap(run) - ->E.R2.fmap(toFloat) - ->E.R.toExn + distOp(dist1, dist2)->E.R2.fmap(mean)->E.R2.fmap(run)->E.R2.fmap(toFloat)->E.R.toExn let expected = floatOp(runMean(dist1), runMean(dist2)) switch received { | None => expectImpossiblePath(description) - | Some(x) => expectErrorToBeBounded(x, expected, ~epsilon=epsilon) + | Some(x) => expectErrorToBeBounded(x, expected, ~epsilon) } } } @@ -79,58 +78,67 @@ let algebraicPower = algebraicPower(~env) let {testOperationMean, distributions, pairsOfDifferentDistributions, epsilon} = module(Internals) describe("Means invariant", () => { - describe("for addition", () => { - let testAdditionMean = testOperationMean(algebraicAdd, "algebraicAdd", \"+.", ~epsilon=epsilon) - + let testAdditionMean = testOperationMean(algebraicAdd, "algebraicAdd", \"+.", ~epsilon) + testAll("of two of the same distribution", distributions, dist => { - E.R.liftM2(testAdditionMean, dist, dist) -> E.R.toExn + E.R.liftM2(testAdditionMean, dist, dist)->E.R.toExn }) testAll("of two different distributions", pairsOfDifferentDistributions, dists => { let (dist1, dist2) = dists - E.R.liftM2(testAdditionMean, dist1, dist2) -> E.R.toExn + E.R.liftM2(testAdditionMean, dist1, dist2)->E.R.toExn }) testAll("of two difference distributions", pairsOfDifferentDistributions, dists => { let (dist1, dist2) = dists - E.R.liftM2(testAdditionMean, dist2, dist1) -> E.R.toExn + E.R.liftM2(testAdditionMean, dist2, dist1)->E.R.toExn }) }) describe("for subtraction", () => { - let testSubtractionMean = testOperationMean(algebraicSubtract, "algebraicSubtract", \"-.", ~epsilon=epsilon) + let testSubtractionMean = testOperationMean( + algebraicSubtract, + "algebraicSubtract", + \"-.", + ~epsilon, + ) testAll("of two of the same distribution", distributions, dist => { - E.R.liftM2(testSubtractionMean, dist, dist) -> E.R.toExn + E.R.liftM2(testSubtractionMean, dist, dist)->E.R.toExn }) testAll("of two different distributions", pairsOfDifferentDistributions, dists => { let (dist1, dist2) = dists - E.R.liftM2(testSubtractionMean, dist1, dist2) -> E.R.toExn + E.R.liftM2(testSubtractionMean, dist1, dist2)->E.R.toExn }) testAll("of two different distributions", pairsOfDifferentDistributions, dists => { let (dist1, dist2) = dists - E.R.liftM2(testSubtractionMean, dist2, dist1) -> E.R.toExn + E.R.liftM2(testSubtractionMean, dist2, dist1)->E.R.toExn }) }) describe("for multiplication", () => { - let testMultiplicationMean = testOperationMean(algebraicMultiply, "algebraicMultiply", \"*.", ~epsilon=epsilon) + let testMultiplicationMean = testOperationMean( + algebraicMultiply, + "algebraicMultiply", + \"*.", + ~epsilon, + ) testAll("of two of the same distribution", distributions, dist => { - E.R.liftM2(testMultiplicationMean, dist, dist) -> E.R.toExn + E.R.liftM2(testMultiplicationMean, dist, dist)->E.R.toExn }) testAll("of two different distributions", pairsOfDifferentDistributions, dists => { let (dist1, dist2) = dists - E.R.liftM2(testMultiplicationMean, dist1, dist2) -> E.R.toExn + E.R.liftM2(testMultiplicationMean, dist1, dist2)->E.R.toExn }) testAll("of two different distributions", pairsOfDifferentDistributions, dists => { let (dist1, dist2) = dists - E.R.liftM2(testMultiplicationMean, dist2, dist1) -> E.R.toExn + E.R.liftM2(testMultiplicationMean, dist2, dist1)->E.R.toExn }) }) }) diff --git a/packages/squiggle-lang/__tests__/TestHelpers.res b/packages/squiggle-lang/__tests__/TestHelpers.res index bff21805..29795fcf 100644 --- a/packages/squiggle-lang/__tests__/TestHelpers.res +++ b/packages/squiggle-lang/__tests__/TestHelpers.res @@ -8,7 +8,7 @@ let expectErrorToBeBounded = (received, expected, ~epsilon) => { } else { distance /. Js.Math.abs_float(expected) } - error -> expect -> toBeLessThan(epsilon) + error->expect->toBeLessThan(epsilon) } let makeTest = (~only=false, str, item1, item2) => diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res index 918c4b70..b0ce84e3 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res @@ -117,7 +117,8 @@ module Helpers = { | Error(err) => GenDistError(ArgumentError(err)) } } - | Some(EvDistribution(b)) => switch parseDistributionArray(args) { + | Some(EvDistribution(b)) => + switch parseDistributionArray(args) { | Ok(distributions) => mixtureWithDefaultWeights(distributions) | Error(err) => GenDistError(ArgumentError(err)) } diff --git a/packages/squiggle-lang/src/rescript/Utility/E.res b/packages/squiggle-lang/src/rescript/Utility/E.res index cb921c39..24e7947c 100644 --- a/packages/squiggle-lang/src/rescript/Utility/E.res +++ b/packages/squiggle-lang/src/rescript/Utility/E.res @@ -215,8 +215,8 @@ module R2 = { | Ok(r) => Ok(r) | Error(e) => map(e) } - - let fmap2 = (xR, f) => + + let fmap2 = (xR, f) => switch xR { | Ok(x) => x->Ok | Error(x) => x->f->Error From 99d1c345c53afff4e14903c0002358845b22fc2a Mon Sep 17 00:00:00 2001 From: Quinn Dougherty Date: Wed, 13 Apr 2022 19:58:36 -0400 Subject: [PATCH 3/4] CR comments --- .../Distributions/Invariants/Means_test.res | 54 +++++++++++-------- .../squiggle-lang/__tests__/TestHelpers.res | 11 ++-- 2 files changed, 39 insertions(+), 26 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Distributions/Invariants/Means_test.res b/packages/squiggle-lang/__tests__/Distributions/Invariants/Means_test.res index a499565b..22a71349 100644 --- a/packages/squiggle-lang/__tests__/Distributions/Invariants/Means_test.res +++ b/packages/squiggle-lang/__tests__/Distributions/Invariants/Means_test.res @@ -13,7 +13,7 @@ open Expect open TestHelpers module Internals = { - let epsilon = 1e3 + let epsilon = 1e1 let mean = GenericDist_Types.Constructors.UsingDists.mean @@ -47,8 +47,8 @@ module Internals = { dist2': SymbolicDistTypes.symbolicDist, ~epsilon: float, ) => { - let dist1 = dist1'->DistributionTypes.Symbolic // ->DistributionTypes.Other - let dist2 = dist2'->DistributionTypes.Symbolic // ->DistributionTypes.Other + let dist1 = dist1'->DistributionTypes.Symbolic + let dist2 = dist2'->DistributionTypes.Symbolic let received = distOp(dist1, dist2)->E.R2.fmap(mean)->E.R2.fmap(run)->E.R2.fmap(toFloat)->E.R.toExn let expected = floatOp(runMean(dist1), runMean(dist2)) @@ -81,19 +81,23 @@ describe("Means invariant", () => { describe("for addition", () => { let testAdditionMean = testOperationMean(algebraicAdd, "algebraicAdd", \"+.", ~epsilon) - testAll("of two of the same distribution", distributions, dist => { + testAll("with two of the same distribution", distributions, dist => { E.R.liftM2(testAdditionMean, dist, dist)->E.R.toExn }) - testAll("of two different distributions", pairsOfDifferentDistributions, dists => { + testAll("with two different distributions", pairsOfDifferentDistributions, dists => { let (dist1, dist2) = dists E.R.liftM2(testAdditionMean, dist1, dist2)->E.R.toExn }) - testAll("of two difference distributions", pairsOfDifferentDistributions, dists => { - let (dist1, dist2) = dists - E.R.liftM2(testAdditionMean, dist2, dist1)->E.R.toExn - }) + testAll( + "with two different distributions in swapped order", + pairsOfDifferentDistributions, + dists => { + let (dist1, dist2) = dists + E.R.liftM2(testAdditionMean, dist2, dist1)->E.R.toExn + }, + ) }) describe("for subtraction", () => { @@ -104,19 +108,23 @@ describe("Means invariant", () => { ~epsilon, ) - testAll("of two of the same distribution", distributions, dist => { + testAll("with two of the same distribution", distributions, dist => { E.R.liftM2(testSubtractionMean, dist, dist)->E.R.toExn }) - testAll("of two different distributions", pairsOfDifferentDistributions, dists => { + testAll("with two different distributions", pairsOfDifferentDistributions, dists => { let (dist1, dist2) = dists E.R.liftM2(testSubtractionMean, dist1, dist2)->E.R.toExn }) - testAll("of two different distributions", pairsOfDifferentDistributions, dists => { - let (dist1, dist2) = dists - E.R.liftM2(testSubtractionMean, dist2, dist1)->E.R.toExn - }) + testAll( + "with two different distributions in swapped order", + pairsOfDifferentDistributions, + dists => { + let (dist1, dist2) = dists + E.R.liftM2(testSubtractionMean, dist2, dist1)->E.R.toExn + }, + ) }) describe("for multiplication", () => { @@ -127,18 +135,22 @@ describe("Means invariant", () => { ~epsilon, ) - testAll("of two of the same distribution", distributions, dist => { + testAll("with two of the same distribution", distributions, dist => { E.R.liftM2(testMultiplicationMean, dist, dist)->E.R.toExn }) - testAll("of two different distributions", pairsOfDifferentDistributions, dists => { + testAll("with two different distributions", pairsOfDifferentDistributions, dists => { let (dist1, dist2) = dists E.R.liftM2(testMultiplicationMean, dist1, dist2)->E.R.toExn }) - testAll("of two different distributions", pairsOfDifferentDistributions, dists => { - let (dist1, dist2) = dists - E.R.liftM2(testMultiplicationMean, dist2, dist1)->E.R.toExn - }) + testAll( + "with two different distributions in swapped order", + pairsOfDifferentDistributions, + dists => { + let (dist1, dist2) = dists + E.R.liftM2(testMultiplicationMean, dist2, dist1)->E.R.toExn + }, + ) }) }) diff --git a/packages/squiggle-lang/__tests__/TestHelpers.res b/packages/squiggle-lang/__tests__/TestHelpers.res index 29795fcf..9369a3a0 100644 --- a/packages/squiggle-lang/__tests__/TestHelpers.res +++ b/packages/squiggle-lang/__tests__/TestHelpers.res @@ -3,11 +3,12 @@ open Expect let expectErrorToBeBounded = (received, expected, ~epsilon) => { let distance = Js.Math.abs_float(received -. expected) - let error = if expected < epsilon ** 2.5 { - distance /. epsilon - } else { - distance /. Js.Math.abs_float(expected) - } + let expectedAbs = Js.Math.abs_float(expected) + let normalizingDenom = Js.Math.max_float( + expectedAbs, + epsilon < 1.0 ? epsilon ** 2.0 : epsilon ** -2.0, + ) + let error = distance /. normalizingDenom error->expect->toBeLessThan(epsilon) } From b3c0adcd307d316d8df2de98b55c00af5a7959af Mon Sep 17 00:00:00 2001 From: Quinn Dougherty Date: Wed, 13 Apr 2022 20:58:16 -0400 Subject: [PATCH 4/4] last CR comments --- .../Distributions/Invariants/Means_test.res | 8 ++++---- packages/squiggle-lang/__tests__/TestHelpers.res | 16 ++++++++++++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Distributions/Invariants/Means_test.res b/packages/squiggle-lang/__tests__/Distributions/Invariants/Means_test.res index 22a71349..e879b520 100644 --- a/packages/squiggle-lang/__tests__/Distributions/Invariants/Means_test.res +++ b/packages/squiggle-lang/__tests__/Distributions/Invariants/Means_test.res @@ -13,7 +13,7 @@ open Expect open TestHelpers module Internals = { - let epsilon = 1e1 + let epsilon = 5e1 let mean = GenericDist_Types.Constructors.UsingDists.mean @@ -21,12 +21,12 @@ module Internals = { `${algebraicOp} has`->expect->toEqual("failed") let distributions = list{ - normalMake(0.0, 1e0), + normalMake(4e0, 1e0), betaMake(2e0, 4e0), exponentialMake(1.234e0), uniformMake(7e0, 1e1), // cauchyMake(1e0, 1e0), - lognormalMake(1e0, 1e0), + lognormalMake(2e0, 1e0), triangularMake(1e0, 1e1, 5e1), Ok(floatMake(1e1)), } @@ -77,7 +77,7 @@ let algebraicPower = algebraicPower(~env) let {testOperationMean, distributions, pairsOfDifferentDistributions, epsilon} = module(Internals) -describe("Means invariant", () => { +describe("Means are invariant", () => { describe("for addition", () => { let testAdditionMean = testOperationMean(algebraicAdd, "algebraicAdd", \"+.", ~epsilon) diff --git a/packages/squiggle-lang/__tests__/TestHelpers.res b/packages/squiggle-lang/__tests__/TestHelpers.res index 9369a3a0..5147857b 100644 --- a/packages/squiggle-lang/__tests__/TestHelpers.res +++ b/packages/squiggle-lang/__tests__/TestHelpers.res @@ -1,13 +1,21 @@ open Jest open Expect +/* +This encodes the expression for percent error +The test says "the percent error of received against expected is bounded by epsilon" + +However, the semantics are degraded by catching some numerical instability: +when expected is too small, the return of this function might blow up to infinity. +So we capture that by taking the max of abs(expected) against a 1. + +A sanity check of this function would be welcome, in general it is a better way of approaching +squiggle-lang tests than toBeSoCloseTo. +*/ let expectErrorToBeBounded = (received, expected, ~epsilon) => { let distance = Js.Math.abs_float(received -. expected) let expectedAbs = Js.Math.abs_float(expected) - let normalizingDenom = Js.Math.max_float( - expectedAbs, - epsilon < 1.0 ? epsilon ** 2.0 : epsilon ** -2.0, - ) + let normalizingDenom = Js.Math.max_float(expectedAbs, 1e0) let error = distance /. normalizingDenom error->expect->toBeLessThan(epsilon) }