Ran yarn format

This commit is contained in:
Quinn Dougherty 2022-04-13 01:02:53 -04:00
parent 8287f51aae
commit de81928ea9
8 changed files with 512 additions and 457 deletions

View File

@ -11,4 +11,4 @@ let triangularDist: GenericDist_Types.genericDist = Symbolic(
) )
let exponentialDist: GenericDist_Types.genericDist = Symbolic(#Exponential({rate: 2.0})) let exponentialDist: GenericDist_Types.genericDist = Symbolic(#Exponential({rate: 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 floatDist: GenericDist_Types.genericDist = Symbolic(#Float(1e1)) let floatDist: GenericDist_Types.genericDist = Symbolic(#Float(1e1))

View File

@ -7,25 +7,25 @@ open Expect
open TestHelpers open TestHelpers
let { let {
normalDist5, // mean=5, stdev=2 normalDist5, // mean=5, stdev=2
normalDist10, // mean=10, stdev=2 normalDist10, // mean=10, stdev=2
normalDist20, // mean=20, stdev=2 normalDist20, // mean=20, stdev=2
normalDist, // mean=5; stdev=2 normalDist, // mean=5; stdev=2
uniformDist, // low=9; high=10 uniformDist, // low=9; high=10
betaDist, // alpha=2; beta=5 betaDist, // alpha=2; beta=5
lognormalDist, // mu=0; sigma=1 lognormalDist, // mu=0; sigma=1
cauchyDist, // local=1; scale=1 cauchyDist, // local=1; scale=1
triangularDist, // low=1; medium=2; high=3; triangularDist, // low=1; medium=2; high=3;
exponentialDist, // rate=2 exponentialDist, // rate=2
} = module(GenericDist_Fixtures) } = module(GenericDist_Fixtures)
let { let {
algebraicAdd, algebraicAdd,
algebraicMultiply, algebraicMultiply,
algebraicDivide, algebraicDivide,
algebraicSubtract, algebraicSubtract,
algebraicLogarithm, algebraicLogarithm,
algebraicPower algebraicPower,
} = module(DistributionOperation.Constructors) } = module(DistributionOperation.Constructors)
let algebraicAdd = algebraicAdd(~env) let algebraicAdd = algebraicAdd(~env)
@ -36,283 +36,330 @@ let algebraicLogarithm = algebraicLogarithm(~env)
let algebraicPower = algebraicPower(~env) let algebraicPower = algebraicPower(~env)
describe("(Algebraic) addition of distributions", () => { describe("(Algebraic) addition of distributions", () => {
describe("mean", () => {
describe("mean", () => { test("normal(mean=5) + normal(mean=20)", () => {
test("normal(mean=5) + normal(mean=20)", () => { normalDist5
normalDist5 ->algebraicAdd(normalDist20)
-> algebraicAdd(normalDist20) ->E.R2.fmap(GenericDist_Types.Constructors.UsingDists.mean)
-> E.R2.fmap(GenericDist_Types.Constructors.UsingDists.mean) ->E.R2.fmap(run)
-> E.R2.fmap(run) ->E.R2.fmap(toFloat)
-> E.R2.fmap(toFloat) ->E.R.toExn
-> E.R.toExn ->expect
-> expect ->toBe(Some(2.5e1))
-> toBe(Some(2.5e1))
})
test("uniform(low=9, high=10) + beta(alpha=2, beta=5)", () => {
// let uniformMean = (9.0 +. 10.0) /. 2.0
// let betaMean = 1.0 /. (1.0 +. 5.0 /. 2.0)
let received = uniformDist
-> algebraicAdd(betaDist)
-> E.R2.fmap(GenericDist_Types.Constructors.UsingDists.mean)
-> E.R2.fmap(run)
-> E.R2.fmap(toFloat)
-> E.R.toExn
switch received {
| None => "algebraicAdd has" -> expect -> toBe("failed")
// This is nondeterministic, we could be in a situation where ci fails but you click rerun and it passes, which is bad.
// sometimes it works with ~digits=2.
| Some(x) => x -> expect -> toBeSoCloseTo(0.01927225696028752, ~digits=1) // (uniformMean +. betaMean)
}
})
test("beta(alpha=2, beta=5) + uniform(low=9, high=10)", () => {
// let uniformMean = (9.0 +. 10.0) /. 2.0
// let betaMean = 1.0 /. (1.0 +. 5.0 /. 2.0)
let received = betaDist
-> algebraicAdd(uniformDist)
-> E.R2.fmap(GenericDist_Types.Constructors.UsingDists.mean)
-> E.R2.fmap(run)
-> E.R2.fmap(toFloat)
-> E.R.toExn
switch received {
| None => "algebraicAdd has" -> expect -> toBe("failed")
// This is nondeterministic, we could be in a situation where ci fails but you click rerun and it passes, which is bad.
// sometimes it works with ~digits=2.
| Some(x) => x -> expect -> toBeSoCloseTo(0.019275414920485248, ~digits=1) // (uniformMean +. betaMean)
}
})
})
describe("pdf", () => {
// TEST IS WRONG. SEE STDEV ADDITION EXPRESSION.
testAll("(normal(mean=5) + normal(mean=5)).pdf (imprecise)", list{8e0, 1e1, 1.2e1, 1.4e1}, x => {
let received = normalDist10 // this should be normal(10, sqrt(8))
-> Ok
-> E.R2.fmap(d => GenericDist_Types.Constructors.UsingDists.pdf(d, x))
-> E.R2.fmap(run)
-> E.R2.fmap(toFloat)
-> E.R.toOption
-> E.O.flatten
let calculated = normalDist5
-> algebraicAdd(normalDist5)
-> E.R2.fmap(d => GenericDist_Types.Constructors.UsingDists.pdf(d, x))
-> E.R2.fmap(run)
-> E.R2.fmap(toFloat)
-> E.R.toOption
-> E.O.flatten
switch received {
| None => "this branch occurs when the dispatch to Jstat on trusted input fails." -> expect -> toBe("never")
| Some(x) => switch calculated {
| None => "algebraicAdd has" -> expect -> toBe("failed")
| Some(y) => x -> expect -> toBeSoCloseTo(y, ~digits=0)
}
}
})
test("(normal(mean=10) + normal(mean=10)).pdf(1.9e1)", () => {
let received = normalDist20
-> Ok
-> E.R2.fmap(d => GenericDist_Types.Constructors.UsingDists.pdf(d, 1.9e1))
-> E.R2.fmap(run)
-> E.R2.fmap(toFloat)
-> E.R.toOption
-> E.O.flatten
let calculated = normalDist10
-> algebraicAdd(normalDist10)
-> E.R2.fmap(d => GenericDist_Types.Constructors.UsingDists.pdf(d, 1.9e1))
-> E.R2.fmap(run)
-> E.R2.fmap(toFloat)
-> E.R.toOption
-> E.O.flatten
switch received {
| None => "this branch occurs when the dispatch to Jstat on trusted input fails." -> expect -> toBe("never")
| Some(x) => switch calculated {
| None => "algebraicAdd has" -> expect -> toBe("failed")
| Some(y) => x -> expect -> toBeSoCloseTo(y, ~digits=1)
}
}
})
test("(uniform(low=9, high=10) + beta(alpha=2, beta=5)).pdf(10)", () => {
let received = uniformDist
-> algebraicAdd(betaDist)
-> E.R2.fmap(d => GenericDist_Types.Constructors.UsingDists.pdf(d, 1e1))
-> E.R2.fmap(run)
-> E.R2.fmap(toFloat)
-> E.R.toExn
switch received {
| None => "algebraicAdd has" -> expect -> toBe("failed")
// This is nondeterministic, we could be in a situation where ci fails but you click rerun and it passes, which is bad.
// sometimes it works with ~digits=4.
| Some(x) => x -> expect -> toBeSoCloseTo(0.001978994877226945, ~digits=3)
}
})
test("(beta(alpha=2, beta=5) + uniform(low=9, high=10)).pdf(10)", () => {
let received = betaDist
-> algebraicAdd(uniformDist)
-> E.R2.fmap(d => GenericDist_Types.Constructors.UsingDists.pdf(d, 1e1))
-> E.R2.fmap(run)
-> E.R2.fmap(toFloat)
-> E.R.toExn
switch received {
| None => "algebraicAdd has" -> expect -> toBe("failed")
// This is nondeterministic, we could be in a situation where ci fails but you click rerun and it passes, which is bad.
// sometimes it works with ~digits=4.
| Some(x) => x -> expect -> toBeSoCloseTo(0.001978994877226945, ~digits=3)
}
})
})
describe("cdf", () => {
testAll("(normal(mean=5) + normal(mean=5)).cdf (imprecise)", list{6e0, 8e0, 1e1, 1.2e1}, x => {
let received = normalDist10
-> Ok
-> E.R2.fmap(d => GenericDist_Types.Constructors.UsingDists.cdf(d, x))
-> E.R2.fmap(run)
-> E.R2.fmap(toFloat)
-> E.R.toOption
-> E.O.flatten
let calculated = normalDist5
-> algebraicAdd(normalDist5)
-> E.R2.fmap(d => GenericDist_Types.Constructors.UsingDists.cdf(d, x))
-> E.R2.fmap(run)
-> E.R2.fmap(toFloat)
-> E.R.toOption
-> E.O.flatten
switch received {
| None => "this branch occurs when the dispatch to Jstat on trusted input fails." -> expect -> toBe("never")
| Some(x) => switch calculated {
| None => "algebraicAdd has" -> expect -> toBe("failed")
| Some(y) => x -> expect -> toBeSoCloseTo(y, ~digits=0)
}
}
})
test("(normal(mean=10) + normal(mean=10)).cdf(1.25e1)", () => {
let received = normalDist20
-> Ok
-> E.R2.fmap(d => GenericDist_Types.Constructors.UsingDists.cdf(d, 1.25e1))
-> E.R2.fmap(run)
-> E.R2.fmap(toFloat)
-> E.R.toOption
-> E.O.flatten
let calculated = normalDist10
-> algebraicAdd(normalDist10)
-> E.R2.fmap(d => GenericDist_Types.Constructors.UsingDists.cdf(d, 1.25e1))
-> E.R2.fmap(run)
-> E.R2.fmap(toFloat)
-> E.R.toOption
-> E.O.flatten
switch received {
| None => "this branch occurs when the dispatch to Jstat on trusted input fails." -> expect -> toBe("never")
| Some(x) => switch calculated {
| None => "algebraicAdd has" -> expect -> toBe("failed")
| Some(y) => x -> expect -> toBeSoCloseTo(y, ~digits=2)
}
}
})
test("(uniform(low=9, high=10) + beta(alpha=2, beta=5)).cdf(10)", () => {
let received = uniformDist
-> algebraicAdd(betaDist)
-> E.R2.fmap(d => GenericDist_Types.Constructors.UsingDists.cdf(d, 1e1))
-> E.R2.fmap(run)
-> E.R2.fmap(toFloat)
-> E.R.toExn
switch received {
| None => "algebraicAdd has" -> expect -> toBe("failed")
// This is nondeterministic, we could be in a situation where ci fails but you click rerun and it passes, which is bad.
// sometimes it works with ~digits=4.
| Some(x) => x -> expect -> toBeSoCloseTo(0.0013961779932477507, ~digits=4)
}
})
test("(beta(alpha=2, beta=5) + uniform(low=9, high=10)).cdf(10)", () => {
let received = betaDist
-> algebraicAdd(uniformDist)
-> E.R2.fmap(d => GenericDist_Types.Constructors.UsingDists.cdf(d, 1e1))
-> E.R2.fmap(run)
-> E.R2.fmap(toFloat)
-> E.R.toExn
switch received {
| None => "algebraicAdd has" -> expect -> toBe("failed")
// This is nondeterministic, we could be in a situation where ci fails but you click rerun and it passes, which is bad.
// sometimes it works with ~digits=4.
| Some(x) => x -> expect -> toBeSoCloseTo(0.001388898111625753, ~digits=3)
}
})
}) })
describe("inv", () => { test("uniform(low=9, high=10) + beta(alpha=2, beta=5)", () => {
testAll("(normal(mean=5) + normal(mean=5)).inv (imprecise)", list{5e-2, 4.2e-3, 9e-3}, x => { // let uniformMean = (9.0 +. 10.0) /. 2.0
let received = normalDist10 // let betaMean = 1.0 /. (1.0 +. 5.0 /. 2.0)
-> Ok let received =
-> E.R2.fmap(d => GenericDist_Types.Constructors.UsingDists.inv(d, x)) uniformDist
-> E.R2.fmap(run) ->algebraicAdd(betaDist)
-> E.R2.fmap(toFloat) ->E.R2.fmap(GenericDist_Types.Constructors.UsingDists.mean)
-> E.R.toOption ->E.R2.fmap(run)
-> E.O.flatten ->E.R2.fmap(toFloat)
let calculated = normalDist5 ->E.R.toExn
-> algebraicAdd(normalDist5) switch received {
-> E.R2.fmap(d => GenericDist_Types.Constructors.UsingDists.inv(d, x)) | None => "algebraicAdd has"->expect->toBe("failed")
-> E.R2.fmap(run) // This is nondeterministic, we could be in a situation where ci fails but you click rerun and it passes, which is bad.
-> E.R2.fmap(toFloat) // sometimes it works with ~digits=2.
-> E.R.toOption | Some(x) => x->expect->toBeSoCloseTo(0.01927225696028752, ~digits=1) // (uniformMean +. betaMean)
-> E.O.flatten }
switch received {
| None => "this branch occurs when the dispatch to Jstat on trusted input fails." -> expect -> toBe("never")
| Some(x) => switch calculated {
| None => "algebraicAdd has" -> expect -> toBe("failed")
| Some(y) => x -> expect -> toBeSoCloseTo(y, ~digits=-1)
}
}
})
test("(normal(mean=10) + normal(mean=10)).inv(1e-1)", () => {
let received = normalDist20
-> Ok
-> E.R2.fmap(d => GenericDist_Types.Constructors.UsingDists.inv(d, 1e-1))
-> E.R2.fmap(run)
-> E.R2.fmap(toFloat)
-> E.R.toOption
-> E.O.flatten
let calculated = normalDist10
-> algebraicAdd(normalDist10)
-> E.R2.fmap(d => GenericDist_Types.Constructors.UsingDists.inv(d, 1e-1))
-> E.R2.fmap(run)
-> E.R2.fmap(toFloat)
-> E.R.toOption
-> E.O.flatten
switch received {
| None => "this branch occurs when the dispatch to Jstat on trusted input fails." -> expect -> toBe("never")
| Some(x) => switch calculated {
| None => "algebraicAdd has" -> expect -> toBe("failed")
| Some(y) => x -> expect -> toBeSoCloseTo(y, ~digits=-1)
}
}
})
test("(uniform(low=9, high=10) + beta(alpha=2, beta=5)).inv(2e-2)", () => {
let received = uniformDist
-> algebraicAdd(betaDist)
-> E.R2.fmap(d => GenericDist_Types.Constructors.UsingDists.inv(d, 2e-2))
-> E.R2.fmap(run)
-> E.R2.fmap(toFloat)
-> E.R.toExn
switch received {
| None => "algebraicAdd has" -> expect -> toBe("failed")
// This is nondeterministic, we could be in a situation where ci fails but you click rerun and it passes, which is bad.
// sometimes it works with ~digits=2.
| Some(x) => x -> expect -> toBeSoCloseTo(10.927078217530806, ~digits=1)
}
})
test("(beta(alpha=2, beta=5) + uniform(low=9, high=10)).inv(2e-2)", () => {
let received = betaDist
-> algebraicAdd(uniformDist)
-> E.R2.fmap(d => GenericDist_Types.Constructors.UsingDists.inv(d, 2e-2))
-> E.R2.fmap(run)
-> E.R2.fmap(toFloat)
-> E.R.toExn
switch received {
| None => "algebraicAdd has" -> expect -> toBe("failed")
// This is nondeterministic, we could be in a situation where ci fails but you click rerun and it passes, which is bad.
// sometimes it works with ~digits=2.
| Some(x) => x -> expect -> toBeSoCloseTo(10.915396627014363, ~digits=0)
}
})
}) })
}) test("beta(alpha=2, beta=5) + uniform(low=9, high=10)", () => {
// let uniformMean = (9.0 +. 10.0) /. 2.0
// let betaMean = 1.0 /. (1.0 +. 5.0 /. 2.0)
let received =
betaDist
->algebraicAdd(uniformDist)
->E.R2.fmap(GenericDist_Types.Constructors.UsingDists.mean)
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toExn
switch received {
| None => "algebraicAdd has"->expect->toBe("failed")
// This is nondeterministic, we could be in a situation where ci fails but you click rerun and it passes, which is bad.
// sometimes it works with ~digits=2.
| Some(x) => x->expect->toBeSoCloseTo(0.019275414920485248, ~digits=1) // (uniformMean +. betaMean)
}
})
})
describe("pdf", () => {
// TEST IS WRONG. SEE STDEV ADDITION EXPRESSION.
testAll(
"(normal(mean=5) + normal(mean=5)).pdf (imprecise)",
list{8e0, 1e1, 1.2e1, 1.4e1},
x => {
let received =
normalDist10 // this should be normal(10, sqrt(8))
->Ok
->E.R2.fmap(d => GenericDist_Types.Constructors.UsingDists.pdf(d, x))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toOption
->E.O.flatten
let calculated =
normalDist5
->algebraicAdd(normalDist5)
->E.R2.fmap(d => GenericDist_Types.Constructors.UsingDists.pdf(d, x))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toOption
->E.O.flatten
switch received {
| None =>
"this branch occurs when the dispatch to Jstat on trusted input fails."
->expect
->toBe("never")
| Some(x) =>
switch calculated {
| None => "algebraicAdd has"->expect->toBe("failed")
| Some(y) => x->expect->toBeSoCloseTo(y, ~digits=0)
}
}
},
)
test("(normal(mean=10) + normal(mean=10)).pdf(1.9e1)", () => {
let received =
normalDist20
->Ok
->E.R2.fmap(d => GenericDist_Types.Constructors.UsingDists.pdf(d, 1.9e1))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toOption
->E.O.flatten
let calculated =
normalDist10
->algebraicAdd(normalDist10)
->E.R2.fmap(d => GenericDist_Types.Constructors.UsingDists.pdf(d, 1.9e1))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toOption
->E.O.flatten
switch received {
| None =>
"this branch occurs when the dispatch to Jstat on trusted input fails."
->expect
->toBe("never")
| Some(x) =>
switch calculated {
| None => "algebraicAdd has"->expect->toBe("failed")
| Some(y) => x->expect->toBeSoCloseTo(y, ~digits=1)
}
}
})
test("(uniform(low=9, high=10) + beta(alpha=2, beta=5)).pdf(10)", () => {
let received =
uniformDist
->algebraicAdd(betaDist)
->E.R2.fmap(d => GenericDist_Types.Constructors.UsingDists.pdf(d, 1e1))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toExn
switch received {
| None => "algebraicAdd has"->expect->toBe("failed")
// This is nondeterministic, we could be in a situation where ci fails but you click rerun and it passes, which is bad.
// sometimes it works with ~digits=4.
| Some(x) => x->expect->toBeSoCloseTo(0.001978994877226945, ~digits=3)
}
})
test("(beta(alpha=2, beta=5) + uniform(low=9, high=10)).pdf(10)", () => {
let received =
betaDist
->algebraicAdd(uniformDist)
->E.R2.fmap(d => GenericDist_Types.Constructors.UsingDists.pdf(d, 1e1))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toExn
switch received {
| None => "algebraicAdd has"->expect->toBe("failed")
// This is nondeterministic, we could be in a situation where ci fails but you click rerun and it passes, which is bad.
// sometimes it works with ~digits=4.
| Some(x) => x->expect->toBeSoCloseTo(0.001978994877226945, ~digits=3)
}
})
})
describe("cdf", () => {
testAll("(normal(mean=5) + normal(mean=5)).cdf (imprecise)", list{6e0, 8e0, 1e1, 1.2e1}, x => {
let received =
normalDist10
->Ok
->E.R2.fmap(d => GenericDist_Types.Constructors.UsingDists.cdf(d, x))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toOption
->E.O.flatten
let calculated =
normalDist5
->algebraicAdd(normalDist5)
->E.R2.fmap(d => GenericDist_Types.Constructors.UsingDists.cdf(d, x))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toOption
->E.O.flatten
switch received {
| None =>
"this branch occurs when the dispatch to Jstat on trusted input fails."
->expect
->toBe("never")
| Some(x) =>
switch calculated {
| None => "algebraicAdd has"->expect->toBe("failed")
| Some(y) => x->expect->toBeSoCloseTo(y, ~digits=0)
}
}
})
test("(normal(mean=10) + normal(mean=10)).cdf(1.25e1)", () => {
let received =
normalDist20
->Ok
->E.R2.fmap(d => GenericDist_Types.Constructors.UsingDists.cdf(d, 1.25e1))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toOption
->E.O.flatten
let calculated =
normalDist10
->algebraicAdd(normalDist10)
->E.R2.fmap(d => GenericDist_Types.Constructors.UsingDists.cdf(d, 1.25e1))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toOption
->E.O.flatten
switch received {
| None =>
"this branch occurs when the dispatch to Jstat on trusted input fails."
->expect
->toBe("never")
| Some(x) =>
switch calculated {
| None => "algebraicAdd has"->expect->toBe("failed")
| Some(y) => x->expect->toBeSoCloseTo(y, ~digits=2)
}
}
})
test("(uniform(low=9, high=10) + beta(alpha=2, beta=5)).cdf(10)", () => {
let received =
uniformDist
->algebraicAdd(betaDist)
->E.R2.fmap(d => GenericDist_Types.Constructors.UsingDists.cdf(d, 1e1))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toExn
switch received {
| None => "algebraicAdd has"->expect->toBe("failed")
// This is nondeterministic, we could be in a situation where ci fails but you click rerun and it passes, which is bad.
// sometimes it works with ~digits=4.
| Some(x) => x->expect->toBeSoCloseTo(0.0013961779932477507, ~digits=4)
}
})
test("(beta(alpha=2, beta=5) + uniform(low=9, high=10)).cdf(10)", () => {
let received =
betaDist
->algebraicAdd(uniformDist)
->E.R2.fmap(d => GenericDist_Types.Constructors.UsingDists.cdf(d, 1e1))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toExn
switch received {
| None => "algebraicAdd has"->expect->toBe("failed")
// This is nondeterministic, we could be in a situation where ci fails but you click rerun and it passes, which is bad.
// sometimes it works with ~digits=4.
| Some(x) => x->expect->toBeSoCloseTo(0.001388898111625753, ~digits=3)
}
})
})
describe("inv", () => {
testAll("(normal(mean=5) + normal(mean=5)).inv (imprecise)", list{5e-2, 4.2e-3, 9e-3}, x => {
let received =
normalDist10
->Ok
->E.R2.fmap(d => GenericDist_Types.Constructors.UsingDists.inv(d, x))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toOption
->E.O.flatten
let calculated =
normalDist5
->algebraicAdd(normalDist5)
->E.R2.fmap(d => GenericDist_Types.Constructors.UsingDists.inv(d, x))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toOption
->E.O.flatten
switch received {
| None =>
"this branch occurs when the dispatch to Jstat on trusted input fails."
->expect
->toBe("never")
| Some(x) =>
switch calculated {
| None => "algebraicAdd has"->expect->toBe("failed")
| Some(y) => x->expect->toBeSoCloseTo(y, ~digits=-1)
}
}
})
test("(normal(mean=10) + normal(mean=10)).inv(1e-1)", () => {
let received =
normalDist20
->Ok
->E.R2.fmap(d => GenericDist_Types.Constructors.UsingDists.inv(d, 1e-1))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toOption
->E.O.flatten
let calculated =
normalDist10
->algebraicAdd(normalDist10)
->E.R2.fmap(d => GenericDist_Types.Constructors.UsingDists.inv(d, 1e-1))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toOption
->E.O.flatten
switch received {
| None =>
"this branch occurs when the dispatch to Jstat on trusted input fails."
->expect
->toBe("never")
| Some(x) =>
switch calculated {
| None => "algebraicAdd has"->expect->toBe("failed")
| Some(y) => x->expect->toBeSoCloseTo(y, ~digits=-1)
}
}
})
test("(uniform(low=9, high=10) + beta(alpha=2, beta=5)).inv(2e-2)", () => {
let received =
uniformDist
->algebraicAdd(betaDist)
->E.R2.fmap(d => GenericDist_Types.Constructors.UsingDists.inv(d, 2e-2))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toExn
switch received {
| None => "algebraicAdd has"->expect->toBe("failed")
// This is nondeterministic, we could be in a situation where ci fails but you click rerun and it passes, which is bad.
// sometimes it works with ~digits=2.
| Some(x) => x->expect->toBeSoCloseTo(10.927078217530806, ~digits=1)
}
})
test("(beta(alpha=2, beta=5) + uniform(low=9, high=10)).inv(2e-2)", () => {
let received =
betaDist
->algebraicAdd(uniformDist)
->E.R2.fmap(d => GenericDist_Types.Constructors.UsingDists.inv(d, 2e-2))
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
->E.R.toExn
switch received {
| None => "algebraicAdd has"->expect->toBe("failed")
// This is nondeterministic, we could be in a situation where ci fails but you click rerun and it passes, which is bad.
// sometimes it works with ~digits=2.
| Some(x) => x->expect->toBeSoCloseTo(10.915396627014363, ~digits=0)
}
})
})
})

View File

@ -3,12 +3,12 @@ open Expect
open TestHelpers open TestHelpers
let { let {
algebraicAdd, algebraicAdd,
algebraicMultiply, algebraicMultiply,
algebraicDivide, algebraicDivide,
algebraicSubtract, algebraicSubtract,
algebraicLogarithm, algebraicLogarithm,
algebraicPower algebraicPower,
} = module(DistributionOperation.Constructors) } = module(DistributionOperation.Constructors)
let algebraicAdd = algebraicAdd(~env) let algebraicAdd = algebraicAdd(~env)
@ -18,147 +18,147 @@ let algebraicSubtract = algebraicSubtract(~env)
let algebraicLogarithm = algebraicLogarithm(~env) let algebraicLogarithm = algebraicLogarithm(~env)
let algebraicPower = algebraicPower(~env) let algebraicPower = algebraicPower(~env)
describe("Mean", () => { describe("Mean", () => {
let mean = GenericDist_Types.Constructors.UsingDists.mean
let mean = GenericDist_Types.Constructors.UsingDists.mean let runMean: result<DistributionTypes.genericDist, DistributionTypes.error> => float = distR => {
switch distR->E.R2.fmap(mean)->E.R2.fmap(run)->E.R2.fmap(toFloat) {
let runMean: result<DistributionTypes.genericDist, DistributionTypes.error> => float = distR => { | Ok(Some(x)) => x
switch distR->E.R2.fmap(mean)->E.R2.fmap(run)->E.R2.fmap(toFloat) { | _ => 9e99 // We trust input in test fixtures so this won't happen
| Ok(Some(x)) => x
| _ => 9e99 // We trust input in test fixtures so this won't happen
}
} }
}
let impossiblePath: string => assertion = algebraicOp => `${algebraicOp} has`->expect->toEqual("failed")
let distributions = list{ let impossiblePath: string => assertion = algebraicOp =>
normalMake(0.0, 1e0), `${algebraicOp} has`->expect->toEqual("failed")
betaMake(2e0, 4e0),
exponentialMake(1.234e0), let distributions = list{
uniformMake(7e0, 1e1), normalMake(0.0, 1e0),
// cauchyMake(1e0, 1e0), betaMake(2e0, 4e0),
lognormalMake(1e0, 1e0), exponentialMake(1.234e0),
triangularMake(1e0, 1e1, 5e1), uniformMake(7e0, 1e1),
Ok(floatMake(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 digits = -4
describe("addition", () => {
let testAdditionMean = (dist1'', dist2'') => {
let dist1' = E.R.fmap(x => DistributionTypes.Symbolic(x), dist1'')
let dist2' = E.R.fmap(x => DistributionTypes.Symbolic(x), dist2'')
let dist1 = E.R.fmap2(s => DistributionTypes.Other(s), dist1')
let dist2 = E.R.fmap2(s => DistributionTypes.Other(s), dist2')
let received =
E.R.liftJoin2(algebraicAdd, dist1, dist2)
->E.R2.fmap(mean)
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
let expected = runMean(dist1) +. runMean(dist2)
switch received {
| Error(err) => impossiblePath("algebraicAdd")
| Ok(x) =>
switch x {
| None => impossiblePath("algebraicAdd")
| Some(x) => x->expect->toBeSoCloseTo(expected, ~digits)
}
}
} }
let combinations = E.L.combinations2(distributions)
let zipDistsDists = E.L.zip(distributions, distributions)
let digits = -4
describe("addition", () => { testAll("homogeneous addition", zipDistsDists, dists => {
let testAdditionMean = (dist1'', dist2'') => { let (dist1, dist2) = dists
let dist1' = E.R.fmap(x => DistributionTypes.Symbolic(x), dist1'') testAdditionMean(dist1, dist2)
let dist2' = E.R.fmap(x => DistributionTypes.Symbolic(x), dist2'')
let dist1 = E.R.fmap2(s => DistributionTypes.Other(s), dist1')
let dist2 = E.R.fmap2(s => DistributionTypes.Other(s), dist2')
let received = E.R.liftJoin2(algebraicAdd, dist1, dist2)
-> E.R2.fmap(mean)
-> E.R2.fmap(run)
-> E.R2.fmap(toFloat)
let expected = runMean(dist1) +. runMean(dist2)
switch received {
| Error(err) => impossiblePath("algebraicAdd")
| Ok(x) =>
switch x {
| None => impossiblePath("algebraicAdd")
| Some(x) => x->expect->toBeSoCloseTo(expected, ~digits=digits)
}
}
}
testAll("homogeneous addition", zipDistsDists, dists => {
let (dist1, dist2) = dists
testAdditionMean(dist1, dist2)
})
testAll("heterogeneoous addition (1)", combinations, dists => {
let (dist1, dist2) = dists
testAdditionMean(dist1, dist2)
})
testAll("heterogeneoous addition (commuted of 1 (or; 2))", combinations, dists => {
let (dist1, dist2) = dists
testAdditionMean(dist2, dist1)
})
}) })
describe("subtraction", () => { testAll("heterogeneoous addition (1)", combinations, dists => {
let testSubtractionMean = (dist1'', dist2'') => { let (dist1, dist2) = dists
let dist1' = E.R.fmap(x => DistributionTypes.Symbolic(x), dist1'') testAdditionMean(dist1, dist2)
let dist2' = E.R.fmap(x => DistributionTypes.Symbolic(x), dist2'')
let dist1 = E.R.fmap2(s => DistributionTypes.Other(s), dist1')
let dist2 = E.R.fmap2(s => DistributionTypes.Other(s), dist2')
let received = E.R.liftJoin2(algebraicSubtract, dist1, dist2)
-> E.R2.fmap(mean)
-> E.R2.fmap(run)
-> E.R2.fmap(toFloat)
let expected = runMean(dist1) -. runMean(dist2)
switch received {
| Error(err) => impossiblePath("algebraicSubtract")
| Ok(x) =>
switch x {
| None => impossiblePath("algebraicSubtract")
| Some(x) => x->expect->toBeSoCloseTo(expected, ~digits=digits)
}
}
}
testAll("homogeneous subtraction", zipDistsDists, dists => {
let (dist1, dist2) = dists
testSubtractionMean(dist1, dist2)
})
testAll("heterogeneoous subtraction (1)", combinations, dists => {
let (dist1, dist2) = dists
testSubtractionMean(dist1, dist2)
})
testAll("heterogeneoous subtraction (commuted of 1 (or; 2))", combinations, dists => {
let (dist1, dist2) = dists
testSubtractionMean(dist2, dist1)
})
}) })
describe("multiplication", () => { testAll("heterogeneoous addition (commuted of 1 (or; 2))", combinations, dists => {
let testMultiplicationMean = (dist1'', dist2'') => { let (dist1, dist2) = dists
let dist1' = E.R.fmap(x => DistributionTypes.Symbolic(x), dist1'') testAdditionMean(dist2, dist1)
let dist2' = E.R.fmap(x => DistributionTypes.Symbolic(x), dist2'')
let dist1 = E.R.fmap2(s => DistributionTypes.Other(s), dist1')
let dist2 = E.R.fmap2(s => DistributionTypes.Other(s), dist2')
let received = E.R.liftJoin2(algebraicMultiply, dist1, dist2)
-> E.R2.fmap(mean)
-> E.R2.fmap(run)
-> E.R2.fmap(toFloat)
let expected = runMean(dist1) *. runMean(dist2)
switch received {
| Error(err) => impossiblePath("algebraicMultiply")
| Ok(x) =>
switch x {
| None => impossiblePath("algebraicMultiply")
| Some(x) => x->expect->toBeSoCloseTo(expected, ~digits=digits)
}
}
}
testAll("homogeneous subtraction", zipDistsDists, dists => {
let (dist1, dist2) = dists
testMultiplicationMean(dist1, dist2)
})
testAll("heterogeneoous subtraction (1)", combinations, dists => {
let (dist1, dist2) = dists
testMultiplicationMean(dist1, dist2)
})
testAll("heterogeneoous subtraction (commuted of 1 (or; 2))", combinations, dists => {
let (dist1, dist2) = dists
testMultiplicationMean(dist2, dist1)
})
}) })
}) })
describe("subtraction", () => {
let testSubtractionMean = (dist1'', dist2'') => {
let dist1' = E.R.fmap(x => DistributionTypes.Symbolic(x), dist1'')
let dist2' = E.R.fmap(x => DistributionTypes.Symbolic(x), dist2'')
let dist1 = E.R.fmap2(s => DistributionTypes.Other(s), dist1')
let dist2 = E.R.fmap2(s => DistributionTypes.Other(s), dist2')
let received =
E.R.liftJoin2(algebraicSubtract, dist1, dist2)
->E.R2.fmap(mean)
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
let expected = runMean(dist1) -. runMean(dist2)
switch received {
| Error(err) => impossiblePath("algebraicSubtract")
| Ok(x) =>
switch x {
| None => impossiblePath("algebraicSubtract")
| Some(x) => x->expect->toBeSoCloseTo(expected, ~digits)
}
}
}
testAll("homogeneous subtraction", zipDistsDists, dists => {
let (dist1, dist2) = dists
testSubtractionMean(dist1, dist2)
})
testAll("heterogeneoous subtraction (1)", combinations, dists => {
let (dist1, dist2) = dists
testSubtractionMean(dist1, dist2)
})
testAll("heterogeneoous subtraction (commuted of 1 (or; 2))", combinations, dists => {
let (dist1, dist2) = dists
testSubtractionMean(dist2, dist1)
})
})
describe("multiplication", () => {
let testMultiplicationMean = (dist1'', dist2'') => {
let dist1' = E.R.fmap(x => DistributionTypes.Symbolic(x), dist1'')
let dist2' = E.R.fmap(x => DistributionTypes.Symbolic(x), dist2'')
let dist1 = E.R.fmap2(s => DistributionTypes.Other(s), dist1')
let dist2 = E.R.fmap2(s => DistributionTypes.Other(s), dist2')
let received =
E.R.liftJoin2(algebraicMultiply, dist1, dist2)
->E.R2.fmap(mean)
->E.R2.fmap(run)
->E.R2.fmap(toFloat)
let expected = runMean(dist1) *. runMean(dist2)
switch received {
| Error(err) => impossiblePath("algebraicMultiply")
| Ok(x) =>
switch x {
| None => impossiblePath("algebraicMultiply")
| Some(x) => x->expect->toBeSoCloseTo(expected, ~digits)
}
}
}
testAll("homogeneous subtraction", zipDistsDists, dists => {
let (dist1, dist2) = dists
testMultiplicationMean(dist1, dist2)
})
testAll("heterogeneoous subtraction (1)", combinations, dists => {
let (dist1, dist2) = dists
testMultiplicationMean(dist1, dist2)
})
testAll("heterogeneoous subtraction (commuted of 1 (or; 2))", combinations, dists => {
let (dist1, dist2) = dists
testMultiplicationMean(dist2, dist1)
})
})
})

View File

@ -19,15 +19,17 @@ let run = DistributionOperation.run(~env)
let outputMap = fmap(~env) let outputMap = fmap(~env)
let unreachableInTestFileMessage = "Should be impossible to reach (This error is in test file)" let unreachableInTestFileMessage = "Should be impossible to reach (This error is in test file)"
let toExtFloat: option<float> => float = E.O.toExt(unreachableInTestFileMessage) let toExtFloat: option<float> => float = E.O.toExt(unreachableInTestFileMessage)
let toExtDist: option<DistributionTypes.genericDist> => DistributionTypes.genericDist = E.O.toExt(unreachableInTestFileMessage) let toExtDist: option<DistributionTypes.genericDist> => DistributionTypes.genericDist = E.O.toExt(
unreachableInTestFileMessage,
)
// let toExt: option<'a> => 'a = E.O.toExt(unreachableInTestFileMessage) // let toExt: option<'a> => 'a = E.O.toExt(unreachableInTestFileMessage)
let unpackFloat = x => x -> toFloat -> toExtFloat let unpackFloat = x => x->toFloat->toExtFloat
let unpackDist = y => y -> toDist -> toExtDist let unpackDist = y => y->toDist->toExtDist
let mkNormal = (mean, stdev) => DistributionTypes.Symbolic(#Normal({mean: mean, stdev: stdev})) let mkNormal = (mean, stdev) => DistributionTypes.Symbolic(#Normal({mean: mean, stdev: stdev}))
let mkBeta = (alpha, beta) => DistributionTypes.Symbolic(#Beta({alpha: alpha, beta: beta})) let mkBeta = (alpha, beta) => DistributionTypes.Symbolic(#Beta({alpha: alpha, beta: beta}))
let mkExponential = rate => DistributionTypes.Symbolic(#Exponential({rate: rate})) let mkExponential = rate => DistributionTypes.Symbolic(#Exponential({rate: rate}))
let mkUniform = (low, high) => DistributionTypes.Symbolic(#Uniform({low: low, high: high})) let mkUniform = (low, high) => DistributionTypes.Symbolic(#Uniform({low: low, high: high}))
let mkCauchy = (local, scale) => DistributionTypes.Symbolic(#Cauchy({local: local, scale: scale})) let mkCauchy = (local, scale) => DistributionTypes.Symbolic(#Cauchy({local: local, scale: scale}))
let mkLognormal = (mu, sigma) => DistributionTypes.Symbolic(#Lognormal({mu: mu, sigma: sigma})) let mkLognormal = (mu, sigma) => DistributionTypes.Symbolic(#Lognormal({mu: mu, sigma: sigma}))
@ -37,5 +39,5 @@ let exponentialMake = SymbolicDist.Exponential.make
let uniformMake = SymbolicDist.Uniform.make let uniformMake = SymbolicDist.Uniform.make
let cauchyMake = SymbolicDist.Cauchy.make let cauchyMake = SymbolicDist.Cauchy.make
let lognormalMake = SymbolicDist.Lognormal.make let lognormalMake = SymbolicDist.Lognormal.make
let triangularMake = SymbolicDist.Triangular.make let triangularMake = SymbolicDist.Triangular.make
let floatMake = SymbolicDist.Float.make let floatMake = SymbolicDist.Float.make

View File

@ -2,9 +2,9 @@ open Jest
open Expect open Expect
describe("E.L.combinations2", () => { describe("E.L.combinations2", () => {
test("size three", () => { test("size three", () => {
E.L.combinations2(list{"alice", "bob", "eve"}) -> expect -> toEqual( E.L.combinations2(list{"alice", "bob", "eve"})
list{("alice", "bob"), ("alice", "eve"), ("bob", "eve")} ->expect
) ->toEqual(list{("alice", "bob"), ("alice", "eve"), ("bob", "eve")})
}) })
}) })

View File

@ -10,7 +10,7 @@
"test:reducer": "jest --testPathPattern '.*__tests__/Reducer.*'", "test:reducer": "jest --testPathPattern '.*__tests__/Reducer.*'",
"test": "jest", "test": "jest",
"test:watch": "jest --watchAll", "test:watch": "jest --watchAll",
"test:quick": "jest --modulePathIgnorePatterns=__tests__/Distributions/Invariants/*", "test:quick": "jest --modulePathIgnorePatterns=__tests__/Distributions/Invariants/*",
"coverage": "rm -f *.coverage; yarn clean; BISECT_ENABLE=yes yarn build; yarn test; bisect-ppx-report html", "coverage": "rm -f *.coverage; yarn clean; BISECT_ENABLE=yes yarn build; yarn test; bisect-ppx-report html",
"coverage:ci": "yarn clean; BISECT_ENABLE=yes yarn build; yarn test; bisect-ppx-report send-to Codecov", "coverage:ci": "yarn clean; BISECT_ENABLE=yes yarn build; yarn test; bisect-ppx-report send-to Codecov",
"lint:rescript": "./lint.sh", "lint:rescript": "./lint.sh",

View File

@ -141,7 +141,7 @@ module Lognormal = {
} }
let divide = (l1, l2) => { let divide = (l1, l2) => {
let mu = l1.mu -. l2.mu let mu = l1.mu -. l2.mu
// We believe the ratiands will have covariance zero. // We believe the ratiands will have covariance zero.
// See here https://stats.stackexchange.com/questions/21735/what-are-the-mean-and-variance-of-the-ratio-of-two-lognormal-variables for details // See here https://stats.stackexchange.com/questions/21735/what-are-the-mean-and-variance-of-the-ratio-of-two-lognormal-variables for details
let sigma = l1.sigma +. l2.sigma let sigma = l1.sigma +. l2.sigma
#Lognormal({mu: mu, sigma: sigma}) #Lognormal({mu: mu, sigma: sigma})

View File

@ -59,7 +59,7 @@ module O = {
let toExn = Rationale.Option.toExn let toExn = Rationale.Option.toExn
let some = Rationale.Option.some let some = Rationale.Option.some
let firstSome = Rationale.Option.firstSome let firstSome = Rationale.Option.firstSome
let toExt = Rationale.Option.toExn // wanna flag this-- looks like a typo but `Rationale.OptiontoExt` doesn't exist. let toExt = Rationale.Option.toExn // wanna flag this-- looks like a typo but `Rationale.OptiontoExt` doesn't exist.
let flatApply = (fn, b) => Rationale.Option.apply(fn, Some(b)) |> Rationale.Option.flatten let flatApply = (fn, b) => Rationale.Option.apply(fn, Some(b)) |> Rationale.Option.flatten
let flatten = Rationale.Option.flatten let flatten = Rationale.Option.flatten
@ -180,23 +180,29 @@ module R = {
errorCondition(r) ? Error(errorMessage) : Ok(r) errorCondition(r) ? Error(errorMessage) : Ok(r)
let ap = Rationale.Result.ap let ap = Rationale.Result.ap
let ap' = (r, a) => switch r { let ap' = (r, a) =>
switch r {
| Ok(f) => fmap(f, a) | Ok(f) => fmap(f, a)
| Error(err) => Error(err) | Error(err) => Error(err)
} }
// (a1 -> a2 -> r) -> m a1 -> m a2 -> m r // not in Rationale // (a1 -> a2 -> r) -> m a1 -> m a2 -> m r // not in Rationale
let liftM2: (('a, 'b) => 'c, result<'a, 'd>, result<'b, 'd>) => result<'c, 'd> = (op, xR, yR) => { let liftM2: (('a, 'b) => 'c, result<'a, 'd>, result<'b, 'd>) => result<'c, 'd> = (op, xR, yR) => {
ap'(fmap(op, xR), yR) ap'(fmap(op, xR), yR)
} }
let liftJoin2: (('a, 'b) => result<'c, 'd>, result<'a, 'd>, result<'b, 'd>) => result<'c, 'd> = (op, xR, yR) => { let liftJoin2: (('a, 'b) => result<'c, 'd>, result<'a, 'd>, result<'b, 'd>) => result<'c, 'd> = (
op,
xR,
yR,
) => {
bind(liftM2(op, xR, yR), x => x) bind(liftM2(op, xR, yR), x => x)
} }
let fmap2 = (f, r) => switch r { let fmap2 = (f, r) =>
switch r {
| Ok(r) => r->Ok | Ok(r) => r->Ok
| Error(x) => x->f->Error | Error(x) => x->f->Error
} }
} }
module R2 = { module R2 = {
@ -283,8 +289,8 @@ module L = {
let tailSafe = Belt.List.tail let tailSafe = Belt.List.tail
let headExn = Belt.List.headExn let headExn = Belt.List.headExn
let tailExn = Belt.List.tailExn let tailExn = Belt.List.tailExn
let zip = Belt.List.zip let zip = Belt.List.zip
let combinations2: list<'a> => list<('a, 'a)> = xs => { let combinations2: list<'a> => list<('a, 'a)> = xs => {
let rec loop: ('a, list<'a>) => list<('a, 'a)> = (x', xs') => { let rec loop: ('a, list<'a>) => list<('a, 'a)> = (x', xs') => {
let n = length(xs') let n = length(xs')
@ -298,8 +304,8 @@ module L = {
} }
} }
switch (headSafe(xs), tailSafe(xs)) { switch (headSafe(xs), tailSafe(xs)) {
| (Some(x'), Some(xs')) => loop(x', xs') | (Some(x'), Some(xs')) => loop(x', xs')
| (_, _) => list{} | (_, _) => list{}
} }
} }
} }