CR comments from #192
This commit is contained in:
parent
d582e29e8b
commit
72be08a516
|
@ -1,19 +1,8 @@
|
||||||
open Jest
|
open Jest
|
||||||
open Expect
|
open Expect
|
||||||
|
open TestHelpers
|
||||||
|
|
||||||
let env: DistributionOperation.env = {
|
// TODO: use Normal.make (etc.), but preferably after the new validation dispatch is in.
|
||||||
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
|
|
||||||
|
|
||||||
let mkNormal = (mean, stdev) => GenericDist_Types.Symbolic(#Normal({mean: mean, stdev: stdev}))
|
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 mkBeta = (alpha, beta) => GenericDist_Types.Symbolic(#Beta({alpha: alpha, beta: beta}))
|
||||||
let mkExponential = rate => GenericDist_Types.Symbolic(#Exponential({rate: rate}))
|
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", () => {
|
describe("mixture", () => {
|
||||||
testAll("fair mean of two normal distributions", list{(0.0, 1e2), (-1e1, -1e-4), (-1e1, 1e2), (-1e1, 1e1)}, tup => { // should be property
|
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 (mean1, mean2) = tup
|
||||||
let theMean = {
|
let meanValue = {
|
||||||
run(Mixture([(mkNormal(mean1, 9e-1), 0.5), (mkNormal(mean2, 9e-1), 0.5)]))
|
run(Mixture([(mkNormal(mean1, 9e-1), 0.5), (mkNormal(mean2, 9e-1), 0.5)]))
|
||||||
-> outputMap(FromDist(ToFloat(#Mean)))
|
-> 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(
|
testAll(
|
||||||
"weighted mean of a beta and an exponential",
|
"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.
|
// 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)},
|
list{((128.0, 1.0), 2.0), ((2e-1, 64.0), 16.0), ((1e0, 1e0), 64.0)},
|
||||||
tup => {
|
tup => {
|
||||||
let (betaParams, rate) = tup
|
let ((alpha, beta), rate) = tup
|
||||||
let (alpha, beta) = betaParams
|
let betaWeight = 0.25
|
||||||
let theMean = {
|
let exponentialWeight = 0.75
|
||||||
|
let meanValue = {
|
||||||
run(Mixture(
|
run(Mixture(
|
||||||
[
|
[
|
||||||
(mkBeta(alpha, beta), 0.25),
|
(mkBeta(alpha, beta), betaWeight),
|
||||||
(mkExponential(rate), 0.75)
|
(mkExponential(rate), exponentialWeight)
|
||||||
]
|
]
|
||||||
)) -> outputMap(FromDist(ToFloat(#Mean)))
|
)) -> outputMap(FromDist(ToFloat(#Mean)))
|
||||||
}
|
}
|
||||||
theMean
|
let betaMean = 1.0 /. (1.0 +. beta /. alpha)
|
||||||
|
let exponentialMean = 1.0 /. rate
|
||||||
|
meanValue
|
||||||
-> unpackFloat
|
-> unpackFloat
|
||||||
-> expect
|
-> expect
|
||||||
-> toBeSoCloseTo(
|
-> toBeSoCloseTo(
|
||||||
0.25 *. 1.0 /. (1.0 +. beta /. alpha) +. 0.75 *. 1.0 /. rate,
|
betaWeight *. betaMean +. exponentialWeight *. exponentialMean,
|
||||||
~digits=-1
|
~digits=-1
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -59,17 +51,19 @@ describe("mixture", () => {
|
||||||
// Would not survive property tests: very easy to find cases that NaN out.
|
// 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))},
|
list{((-1e2,1e1), (2e0,1e0)), ((-1e-16,1e-16), (1e-8,1e0)), ((0.0,1e0), (1e0,1e-2))},
|
||||||
tup => {
|
tup => {
|
||||||
let (uniformParams, lognormalParams) = tup
|
let ((low, high), (mu, sigma)) = tup
|
||||||
let (low, high) = uniformParams
|
let uniformWeight = 0.6
|
||||||
let (mu, sigma) = lognormalParams
|
let lognormalWeight = 0.4
|
||||||
let theMean = {
|
let meanValue = {
|
||||||
run(Mixture([(mkUniform(low, high), 0.6), (mkLognormal(mu, sigma), 0.4)]))
|
run(Mixture([(mkUniform(low, high), uniformWeight), (mkLognormal(mu, sigma), lognormalWeight)]))
|
||||||
-> outputMap(FromDist(ToFloat(#Mean)))
|
-> outputMap(FromDist(ToFloat(#Mean)))
|
||||||
}
|
}
|
||||||
theMean
|
let uniformMean = (low +. high) /. 2.0
|
||||||
|
let lognormalMean = mu +. sigma ** 2.0 /. 2.0
|
||||||
|
meanValue
|
||||||
-> unpackFloat
|
-> unpackFloat
|
||||||
-> expect
|
-> 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)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,19 +1,14 @@
|
||||||
open Jest
|
open Jest
|
||||||
open Expect
|
open TestHelpers
|
||||||
|
|
||||||
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", () => {
|
describe("Continuous and discrete splits", () => {
|
||||||
makeTest(
|
makeTest(
|
||||||
"check splits one",
|
"splits (1)",
|
||||||
SampleSet.Internals.T.splitContinuousAndDiscrete([1.432, 1.33455, 2.0]),
|
SampleSet.Internals.T.splitContinuousAndDiscrete([1.432, 1.33455, 2.0]),
|
||||||
([1.432, 1.33455, 2.0], E.FloatFloatMap.empty()),
|
([1.432, 1.33455, 2.0], E.FloatFloatMap.empty()),
|
||||||
)
|
)
|
||||||
makeTest(
|
makeTest(
|
||||||
"check splits two",
|
"splits (2)",
|
||||||
SampleSet.Internals.T.splitContinuousAndDiscrete([
|
SampleSet.Internals.T.splitContinuousAndDiscrete([
|
||||||
1.432,
|
1.432,
|
||||||
1.33455,
|
1.33455,
|
||||||
|
|
|
@ -1,34 +1,18 @@
|
||||||
open Jest
|
open Jest
|
||||||
open Expect
|
open Expect
|
||||||
|
open TestHelpers
|
||||||
|
|
||||||
let fnImage = (theFn, inps) => Js.Array.map(theFn, inps)
|
// TODO: use Normal.make (but preferably after teh new validation dispatch is in)
|
||||||
|
|
||||||
let env: DistributionOperation.env = {
|
|
||||||
sampleCount: 100,
|
|
||||||
xyPointLength: 100,
|
|
||||||
}
|
|
||||||
|
|
||||||
let mkNormal = (mean, stdev) => GenericDist_Types.Symbolic(#Normal({mean: mean, stdev: stdev}))
|
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> => float = E.O.toExt(
|
|
||||||
"Should be impossible to reach (This error is in test file)",
|
|
||||||
)
|
|
||||||
let toExtDist: option<GenericDist_Types.genericDist> => 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", () => {
|
describe("(Symbolic) normalize", () => {
|
||||||
testAll("has no impact on normal distributions", list{-1e8, -16.0, -1e-2, 0.0, 1e-4, 32.0, 1e16}, mean => {
|
testAll("has no impact on normal distributions", list{-1e8, -1e-2, 0.0, 1e-4, 1e16}, mean => {
|
||||||
let theNormal = mkNormal(mean, 2.0)
|
let normalValue = mkNormal(mean, 2.0)
|
||||||
let theNormalized = run(FromDist(ToDist(Normalize), theNormal))
|
let normalizedValue = run(FromDist(ToDist(Normalize), normalValue))
|
||||||
theNormalized
|
normalizedValue
|
||||||
-> unpackDist
|
-> unpackDist
|
||||||
-> expect
|
-> 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 => {
|
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}))))
|
let meanValue = 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
|
meanValue -> unpackFloat -> expect -> toBeCloseTo(1.0 /. rate) // https://en.wikipedia.org/wiki/Exponential_distribution#Mean,_variance,_moments,_and_median
|
||||||
})
|
})
|
||||||
|
|
||||||
test("of a cauchy distribution", () => {
|
test("of a cauchy distribution", () => {
|
||||||
let theMean = run(FromDist(ToFloat(#Mean), GenericDist_Types.Symbolic(#Cauchy({local: 1.0, scale: 1.0}))))
|
let meanValue = run(FromDist(ToFloat(#Mean), GenericDist_Types.Symbolic(#Cauchy({local: 1.0, scale: 1.0}))))
|
||||||
theMean
|
meanValue
|
||||||
-> unpackFloat
|
-> unpackFloat
|
||||||
-> expect
|
-> expect
|
||||||
-> toBeCloseTo(2.01868297874546)
|
-> 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 => {
|
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 (low, medium, high) = tup
|
||||||
let theMean = run(FromDist(
|
let meanValue = run(FromDist(
|
||||||
ToFloat(#Mean),
|
ToFloat(#Mean),
|
||||||
GenericDist_Types.Symbolic(#Triangular({low: low, medium: medium, high: high}))
|
GenericDist_Types.Symbolic(#Triangular({low: low, medium: medium, high: high}))
|
||||||
))
|
))
|
||||||
theMean
|
meanValue
|
||||||
-> unpackFloat
|
-> unpackFloat
|
||||||
-> expect
|
-> expect
|
||||||
-> toBeCloseTo((low +. medium +. high) /. 3.0) // https://www.statology.org/triangular-distribution/
|
-> 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.
|
// 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 => {
|
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 (alpha, beta) = tup
|
||||||
let theMean = run(FromDist(
|
let meanValue = run(FromDist(
|
||||||
ToFloat(#Mean),
|
ToFloat(#Mean),
|
||||||
GenericDist_Types.Symbolic(#Beta({alpha: alpha, beta: beta}))
|
GenericDist_Types.Symbolic(#Beta({alpha: alpha, beta: beta}))
|
||||||
))
|
))
|
||||||
theMean
|
meanValue
|
||||||
-> unpackFloat
|
-> unpackFloat
|
||||||
-> expect
|
-> expect
|
||||||
-> toBeCloseTo(1.0 /. (1.0 +. (beta /. alpha))) // https://en.wikipedia.org/wiki/Beta_distribution#Mean
|
-> 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.
|
// 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)", () => {
|
test("of beta(0, 0)", () => {
|
||||||
let theMean = run(FromDist(
|
let meanValue = run(FromDist(
|
||||||
ToFloat(#Mean),
|
ToFloat(#Mean),
|
||||||
GenericDist_Types.Symbolic(#Beta({alpha: 0.0, beta: 0.0}))
|
GenericDist_Types.Symbolic(#Beta({alpha: 0.0, beta: 0.0}))
|
||||||
))
|
))
|
||||||
theMean
|
meanValue
|
||||||
-> unpackFloat
|
-> unpackFloat
|
||||||
-> expect
|
-> expect
|
||||||
-> ExpectJs.toBeFalsy
|
-> 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 => {
|
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 (mu, sigma) = tup
|
||||||
let theMean = run(FromDist(
|
let meanValue = run(FromDist(
|
||||||
ToFloat(#Mean),
|
ToFloat(#Mean),
|
||||||
GenericDist_Types.Symbolic(#Lognormal({mu: mu, sigma: sigma}))
|
GenericDist_Types.Symbolic(#Lognormal({mu: mu, sigma: sigma}))
|
||||||
))
|
))
|
||||||
theMean
|
meanValue
|
||||||
-> unpackFloat
|
-> unpackFloat
|
||||||
-> expect
|
-> expect
|
||||||
-> toBeCloseTo(Js.Math.exp(mu +. sigma ** 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/
|
||||||
|
@ -119,22 +103,22 @@ describe("(Symbolic) mean", () => {
|
||||||
|
|
||||||
testAll("of uniform distributions", list{(1e-5, 12.345), (-1e4, 1e4), (-1e16, -1e2), (5.3e3, 9e9)}, tup => {
|
testAll("of uniform distributions", list{(1e-5, 12.345), (-1e4, 1e4), (-1e16, -1e2), (5.3e3, 9e9)}, tup => {
|
||||||
let (low, high) = tup
|
let (low, high) = tup
|
||||||
let theMean = run(FromDist(
|
let meanValue = run(FromDist(
|
||||||
ToFloat(#Mean),
|
ToFloat(#Mean),
|
||||||
GenericDist_Types.Symbolic(#Uniform({low: low, high: high}))
|
GenericDist_Types.Symbolic(#Uniform({low: low, high: high}))
|
||||||
))
|
))
|
||||||
theMean
|
meanValue
|
||||||
-> unpackFloat
|
-> unpackFloat
|
||||||
-> expect
|
-> expect
|
||||||
-> toBeCloseTo((low +. high) /. 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", () => {
|
test("of a float", () => {
|
||||||
let theMean = run(FromDist(
|
let meanValue = run(FromDist(
|
||||||
ToFloat(#Mean),
|
ToFloat(#Mean),
|
||||||
GenericDist_Types.Symbolic(#Float(7.7))
|
GenericDist_Types.Symbolic(#Float(7.7))
|
||||||
))
|
))
|
||||||
theMean -> unpackFloat -> expect -> toBeCloseTo(7.7)
|
meanValue -> unpackFloat -> expect -> toBeCloseTo(7.7)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
26
packages/squiggle-lang/__tests__/TestHelpers.res
Normal file
26
packages/squiggle-lang/__tests__/TestHelpers.res
Normal file
|
@ -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> => float = E.O.toExt(unreachableInTestFileMessage)
|
||||||
|
let toExtDist: option<GenericDist_Types.genericDist> => 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
|
|
@ -5,4 +5,7 @@ module.exports = {
|
||||||
setupFilesAfterEnv: [
|
setupFilesAfterEnv: [
|
||||||
"<rootdir>/../../node_modules/bisect_ppx/src/runtime/js/jest.bs.js"
|
"<rootdir>/../../node_modules/bisect_ppx/src/runtime/js/jest.bs.js"
|
||||||
],
|
],
|
||||||
|
testPathIgnorePatterns: [
|
||||||
|
"__tests__/TestHelpers.bs.js"
|
||||||
|
],
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue
Block a user