property test framework installed but not used; describe(means) section of unit tests filled out

This commit is contained in:
Quinn Dougherty 2022-04-06 18:57:51 -04:00
parent e42ac0b58d
commit 0a5a8a5198
6 changed files with 121 additions and 10 deletions

View File

@ -13,6 +13,9 @@ Other:
yarn start # listens to files and recompiles at every mutation yarn start # listens to files and recompiles at every mutation
yarn test yarn test
yarn test:watch # keeps an active session and runs all tests at every mutation 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 # TODO: clean up this README.md

View File

@ -1,14 +1,18 @@
open Jest open Jest
open Expect open Expect
open FastCheck
// open Arbitrary
open Property.Sync
let env: DistributionOperation.env = { let env: DistributionOperation.env = {
sampleCount: 100, sampleCount: 100,
xyPointLength: 100, xyPointLength: 100,
} }
let normalDist5: GenericDist_Types.genericDist = Symbolic(#Normal({mean: 5.0, stdev: 2.0})) let mkNormal = (mean, stdev) => GenericDist_Types.Symbolic(#Normal({mean: mean, stdev: stdev}))
let normalDist10: GenericDist_Types.genericDist = Symbolic(#Normal({mean: 10.0, stdev: 2.0})) let normalDist5: GenericDist_Types.genericDist = mkNormal(5.0, 2.0)
let normalDist20: GenericDist_Types.genericDist = Symbolic(#Normal({mean: 20.0, stdev: 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 uniformDist: GenericDist_Types.genericDist = Symbolic(#Uniform({low: 9.0, high: 10.0}))
let {toFloat, toDist, toString, toError} = module(DistributionOperation.Output) let {toFloat, toDist, toString, toError} = module(DistributionOperation.Output)
@ -19,18 +23,99 @@ let outputMap = fmap(~env)
let toExt: option<'a> => 'a = E.O.toExt( let toExt: option<'a> => 'a = E.O.toExt(
"Should be impossible to reach (This error is in test file)", "Should be impossible to reach (This error is in test file)",
) )
let unpackFloat = x => x -> toFloat -> toExt
describe("normalize", () => { describe("normalize", () => {
test("has no impact on normal dist", () => { test("has no impact on normal dist", () => {
let result = run(FromDist(ToDist(Normalize), normalDist5)) let result = run(FromDist(ToDist(Normalize), normalDist5))
expect(result)->toEqual(Dist(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", () => { describe("mean", () => {
test("for a normal distribution", () => { test("of a normal distribution", () => { // should be property
let result = DistributionOperation.run(~env, FromDist(ToFloat(#Mean), normalDist5)) run(FromDist(ToFloat(#Mean), normalDist5)) -> unpackFloat -> expect -> toBeCloseTo(5.0)
expect(result)->toEqual(Float(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)
}) })
}) })

View File

@ -30,6 +30,9 @@
"rationale", "rationale",
"bisect_ppx" "bisect_ppx"
], ],
"bs-dev-dependencies": [
"rescript-fast-check"
],
"gentypeconfig": { "gentypeconfig": {
"language": "typescript", "language": "typescript",
"module": "commonjs", "module": "commonjs",

View File

@ -35,6 +35,7 @@
"docsify": "^4.12.2", "docsify": "^4.12.2",
"gentype": "^4.3.0", "gentype": "^4.3.0",
"jest": "^27.5.1", "jest": "^27.5.1",
"rescript-fast-check": "^1.1.1",
"moduleserve": "0.9.1", "moduleserve": "0.9.1",
"ts-jest": "^27.1.4", "ts-jest": "^27.1.4",
"ts-loader": "^9.2.8", "ts-loader": "^9.2.8",

View File

@ -55,7 +55,7 @@ module Exponential = {
rate: rate, 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 pdf = (x, t: t) => Jstat.Exponential.pdf(x, t.rate)
let cdf = (x, t: t) => Jstat.Exponential.cdf(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) 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 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 inv = (p, t: t) => Jstat.Cauchy.inv(p, t.local, t.scale)
let sample = (t: t) => Jstat.Cauchy.sample(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)` let toString = ({local, scale}: t) => j`Cauchy($local, $scale)`
} }
@ -80,8 +80,8 @@ module Triangular = {
let make = (low, medium, high): result<symbolicDist, string> => let make = (low, medium, high): result<symbolicDist, string> =>
low < medium && medium < high low < medium && medium < high
? Ok(#Triangular({low: low, medium: medium, high: high})) ? Ok(#Triangular({low: low, medium: medium, high: high}))
: Error("Triangular values must be increasing order") : Error("Triangular values must be increasing order.")
let pdf = (x, t: t) => Jstat.Triangular.pdf(x, t.low, t.high, t.medium) 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 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 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) let sample = (t: t) => Jstat.Triangular.sample(t.low, t.high, t.medium)

View File

@ -8392,6 +8392,13 @@ extglob@^2.0.4:
snapdragon "^0.8.1" snapdragon "^0.8.1"
to-regex "^3.0.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: fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3, fast-deep-equal@~3.1.3:
version "3.1.3" version "3.1.3"
resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" 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" resolved "https://registry.yarnpkg.com/pure-color/-/pure-color-1.3.0.tgz#1fe064fb0ac851f0de61320a8bf796836422f33e"
integrity sha1-H+Bk+wrIUfDeYTIKi/eWg2Qi8z4= 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: q@^1.1.2:
version "1.5.1" version "1.5.1"
resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" 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" resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= 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: rescript@^9.1.4:
version "9.1.4" version "9.1.4"
resolved "https://registry.npmjs.org/rescript/-/rescript-9.1.4.tgz" resolved "https://registry.npmjs.org/rescript/-/rescript-9.1.4.tgz"