Merge pull request #181 from QURIresearch/dist-refactor
Rescript Organization Refactor #1
This commit is contained in:
commit
f6ee23f229
|
@ -1,89 +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("PointSetTypes", () =>
|
|
||||||
describe("Domain", () => {
|
|
||||||
let makeComplete = (yPoint, expectation) =>
|
|
||||||
makeTest(
|
|
||||||
"With input: " ++ Js.Float.toString(yPoint),
|
|
||||||
PointSetTypes.Domain.yPointToSubYPoint(Complete, yPoint),
|
|
||||||
expectation,
|
|
||||||
)
|
|
||||||
let makeSingle = (direction: [#left | #right], excludingProbabilityMass, yPoint, expectation) =>
|
|
||||||
makeTest(
|
|
||||||
"Excluding: " ++
|
|
||||||
(Js.Float.toString(excludingProbabilityMass) ++
|
|
||||||
(" and yPoint: " ++ Js.Float.toString(yPoint))),
|
|
||||||
PointSetTypes.Domain.yPointToSubYPoint(
|
|
||||||
direction == #left
|
|
||||||
? LeftLimited({xPoint: 3.0, excludingProbabilityMass: excludingProbabilityMass})
|
|
||||||
: RightLimited({xPoint: 3.0, excludingProbabilityMass: excludingProbabilityMass}),
|
|
||||||
yPoint,
|
|
||||||
),
|
|
||||||
expectation,
|
|
||||||
)
|
|
||||||
let makeDouble = (domain, yPoint, expectation) =>
|
|
||||||
makeTest("Excluding: limits", PointSetTypes.Domain.yPointToSubYPoint(domain, yPoint), expectation)
|
|
||||||
|
|
||||||
describe("With Complete Domain", () => {
|
|
||||||
makeComplete(0.0, Some(0.0))
|
|
||||||
makeComplete(0.6, Some(0.6))
|
|
||||||
makeComplete(1.0, Some(1.0))
|
|
||||||
})
|
|
||||||
describe("With Left Limit", () => {
|
|
||||||
makeSingle(#left, 0.5, 1.0, Some(1.0))
|
|
||||||
makeSingle(#left, 0.5, 0.75, Some(0.5))
|
|
||||||
makeSingle(#left, 0.8, 0.9, Some(0.5))
|
|
||||||
makeSingle(#left, 0.5, 0.4, None)
|
|
||||||
makeSingle(#left, 0.5, 0.5, Some(0.0))
|
|
||||||
})
|
|
||||||
describe("With Right Limit", () => {
|
|
||||||
makeSingle(#right, 0.5, 1.0, None)
|
|
||||||
makeSingle(#right, 0.5, 0.25, Some(0.5))
|
|
||||||
makeSingle(#right, 0.8, 0.5, None)
|
|
||||||
makeSingle(#right, 0.2, 0.2, Some(0.25))
|
|
||||||
makeSingle(#right, 0.5, 0.5, Some(1.0))
|
|
||||||
makeSingle(#right, 0.5, 0.0, Some(0.0))
|
|
||||||
makeSingle(#right, 0.5, 0.5, Some(1.0))
|
|
||||||
})
|
|
||||||
describe("With Left and Right Limit", () => {
|
|
||||||
makeDouble(
|
|
||||||
LeftAndRightLimited(
|
|
||||||
{excludingProbabilityMass: 0.25, xPoint: 3.0},
|
|
||||||
{excludingProbabilityMass: 0.25, xPoint: 10.0},
|
|
||||||
),
|
|
||||||
0.5,
|
|
||||||
Some(0.5),
|
|
||||||
)
|
|
||||||
makeDouble(
|
|
||||||
LeftAndRightLimited(
|
|
||||||
{excludingProbabilityMass: 0.1, xPoint: 3.0},
|
|
||||||
{excludingProbabilityMass: 0.1, xPoint: 10.0},
|
|
||||||
),
|
|
||||||
0.2,
|
|
||||||
Some(0.125),
|
|
||||||
)
|
|
||||||
makeDouble(
|
|
||||||
LeftAndRightLimited(
|
|
||||||
{excludingProbabilityMass: 0.1, xPoint: 3.0},
|
|
||||||
{excludingProbabilityMass: 0.1, xPoint: 10.0},
|
|
||||||
),
|
|
||||||
0.1,
|
|
||||||
Some(0.0),
|
|
||||||
)
|
|
||||||
makeDouble(
|
|
||||||
LeftAndRightLimited(
|
|
||||||
{excludingProbabilityMass: 0.1, xPoint: 3.0},
|
|
||||||
{excludingProbabilityMass: 0.1, xPoint: 10.0},
|
|
||||||
),
|
|
||||||
0.05,
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
)
|
|
|
@ -1,7 +1,7 @@
|
||||||
open Jest
|
open Jest
|
||||||
open Expect
|
open Expect
|
||||||
|
|
||||||
let env: GenericDist_GenericOperation.env = {
|
let env: DistributionOperation.env = {
|
||||||
sampleCount: 100,
|
sampleCount: 100,
|
||||||
xyPointLength: 100,
|
xyPointLength: 100,
|
||||||
}
|
}
|
||||||
|
@ -11,9 +11,9 @@ let normalDist10: GenericDist_Types.genericDist = Symbolic(#Normal({mean: 10.0,
|
||||||
let normalDist20: GenericDist_Types.genericDist = Symbolic(#Normal({mean: 20.0, stdev: 2.0}))
|
let normalDist20: GenericDist_Types.genericDist = Symbolic(#Normal({mean: 20.0, stdev: 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(GenericDist_GenericOperation.Output)
|
let {toFloat, toDist, toString, toError} = module(DistributionOperation.Output)
|
||||||
let {run} = module(GenericDist_GenericOperation)
|
let {run} = module(DistributionOperation)
|
||||||
let {fmap} = module(GenericDist_GenericOperation.Output)
|
let {fmap} = module(DistributionOperation.Output)
|
||||||
let run = run(~env)
|
let run = run(~env)
|
||||||
let outputMap = fmap(~env)
|
let outputMap = fmap(~env)
|
||||||
let toExt: option<'a> => 'a = E.O.toExt(
|
let toExt: option<'a> => 'a = E.O.toExt(
|
||||||
|
@ -29,7 +29,7 @@ describe("normalize", () => {
|
||||||
|
|
||||||
describe("mean", () => {
|
describe("mean", () => {
|
||||||
test("for a normal distribution", () => {
|
test("for a normal distribution", () => {
|
||||||
let result = GenericDist_GenericOperation.run(~env, FromDist(ToFloat(#Mean), normalDist))
|
let result = DistributionOperation.run(~env, FromDist(ToFloat(#Mean), normalDist))
|
||||||
expect(result)->toEqual(Float(5.0))
|
expect(result)->toEqual(Float(5.0))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import {runAll} from '../rescript/ProgramEvaluator.gen';
|
import {runAll} from '../rescript/ProgramEvaluator.gen';
|
||||||
import type { Inputs_SamplingInputs_t as SamplingInputs, exportEnv, exportType, exportDistribution} from '../rescript/ProgramEvaluator.gen';
|
import type { Inputs_SamplingInputs_t as SamplingInputs, exportEnv, exportType, exportDistribution} from '../rescript/ProgramEvaluator.gen';
|
||||||
export type { SamplingInputs, exportEnv, exportDistribution }
|
export type { SamplingInputs, exportEnv, exportDistribution }
|
||||||
export type {t as DistPlus} from '../rescript/pointSetDist/DistPlus.gen';
|
export type {t as DistPlus} from '../rescript/OldInterpreter/DistPlus.gen';
|
||||||
|
|
||||||
export let defaultSamplingInputs : SamplingInputs = {
|
export let defaultSamplingInputs : SamplingInputs = {
|
||||||
sampleCount : 10000,
|
sampleCount : 10000,
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
type genericDist =
|
||||||
|
| PointSet(PointSetTypes.pointSetDist)
|
||||||
|
| SampleSet(array<float>)
|
||||||
|
| Symbolic(SymbolicDistTypes.symbolicDist)
|
||||||
|
|
||||||
|
type error =
|
||||||
|
| NotYetImplemented
|
||||||
|
| Unreachable
|
||||||
|
| DistributionVerticalShiftIsInvalid
|
||||||
|
| Other(string)
|
||||||
|
|
||||||
|
module Operation = {
|
||||||
|
type direction =
|
||||||
|
| Algebraic
|
||||||
|
| Pointwise
|
||||||
|
|
||||||
|
type arithmeticOperation = [
|
||||||
|
| #Add
|
||||||
|
| #Multiply
|
||||||
|
| #Subtract
|
||||||
|
| #Divide
|
||||||
|
| #Exponentiate
|
||||||
|
| #Logarithm
|
||||||
|
]
|
||||||
|
|
||||||
|
let arithmeticToFn = (arithmetic: arithmeticOperation) =>
|
||||||
|
switch arithmetic {
|
||||||
|
| #Add => \"+."
|
||||||
|
| #Multiply => \"*."
|
||||||
|
| #Subtract => \"-."
|
||||||
|
| #Exponentiate => \"**"
|
||||||
|
| #Divide => \"/."
|
||||||
|
| #Logarithm => (a, b) => log(a) /. log(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
type toFloat = [
|
||||||
|
| #Cdf(float)
|
||||||
|
| #Inv(float)
|
||||||
|
| #Pdf(float)
|
||||||
|
| #Mean
|
||||||
|
| #Sample
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
module DistributionOperation = {
|
||||||
|
type toDist =
|
||||||
|
| Normalize
|
||||||
|
| ToPointSet
|
||||||
|
| ToSampleSet(int)
|
||||||
|
| Truncate(option<float>, option<float>)
|
||||||
|
| Inspect
|
||||||
|
|
||||||
|
type toFloatArray = Sample(int)
|
||||||
|
|
||||||
|
type fromDist =
|
||||||
|
| ToFloat(Operation.toFloat)
|
||||||
|
| ToDist(toDist)
|
||||||
|
| ToDistCombination(Operation.direction, Operation.arithmeticOperation, [#Dist(genericDist) | #Float(float)])
|
||||||
|
| ToString
|
||||||
|
|
||||||
|
type singleParamaterFunction =
|
||||||
|
| FromDist(fromDist)
|
||||||
|
| FromFloat(fromDist)
|
||||||
|
|
||||||
|
type genericFunctionCallInfo =
|
||||||
|
| FromDist(fromDist, genericDist)
|
||||||
|
| FromFloat(fromDist, float)
|
||||||
|
| Mixture(array<(genericDist, float)>)
|
||||||
|
|
||||||
|
let distCallToString = (distFunction: fromDist): string =>
|
||||||
|
switch distFunction {
|
||||||
|
| ToFloat(#Cdf(r)) => `cdf(${E.Float.toFixed(r)})`
|
||||||
|
| ToFloat(#Inv(r)) => `inv(${E.Float.toFixed(r)})`
|
||||||
|
| ToFloat(#Mean) => `mean`
|
||||||
|
| ToFloat(#Pdf(r)) => `pdf(${E.Float.toFixed(r)})`
|
||||||
|
| ToFloat(#Sample) => `sample`
|
||||||
|
| ToDist(Normalize) => `normalize`
|
||||||
|
| ToDist(ToPointSet) => `toPointSet`
|
||||||
|
| ToDist(ToSampleSet(r)) => `toSampleSet(${E.I.toString(r)})`
|
||||||
|
| ToDist(Truncate(_, _)) => `truncate`
|
||||||
|
| ToDist(Inspect) => `inspect`
|
||||||
|
| ToString => `toString`
|
||||||
|
| ToDistCombination(Algebraic, _, _) => `algebraic`
|
||||||
|
| ToDistCombination(Pointwise, _, _) => `pointwise`
|
||||||
|
}
|
||||||
|
|
||||||
|
let toString = (d: genericFunctionCallInfo): string =>
|
||||||
|
switch d {
|
||||||
|
| FromDist(f, _) | FromFloat(f, _) => distCallToString(f)
|
||||||
|
| Mixture(_) => `mixture`
|
||||||
|
}
|
||||||
|
}
|
|
@ -30,7 +30,7 @@ let truncate: (
|
||||||
~toPointSetFn: toPointSetFn,
|
~toPointSetFn: toPointSetFn,
|
||||||
~leftCutoff: option<float>=?,
|
~leftCutoff: option<float>=?,
|
||||||
~rightCutoff: option<float>=?,
|
~rightCutoff: option<float>=?,
|
||||||
unit,
|
unit
|
||||||
) => result<t, error>
|
) => result<t, error>
|
||||||
|
|
||||||
let algebraicCombination: (
|
let algebraicCombination: (
|
|
@ -118,13 +118,14 @@ let combineShapesContinuousContinuous = (
|
||||||
| #Logarithm => (m1, m2) => log(m1) /. log(m2)
|
| #Logarithm => (m1, m2) => log(m1) /. log(m2)
|
||||||
} // note: here, mInv2 = mean(1 / t2) ~= 1 / mean(t2)
|
} // note: here, mInv2 = mean(1 / t2) ~= 1 / mean(t2)
|
||||||
|
|
||||||
// TODO: I don't know what the variances are for exponentatiation
|
// TODO: Variances are for exponentatiation or logarithms are almost totally made up and very likely very wrong.
|
||||||
// converts the variances and means of the two inputs into the variance of the output
|
// converts the variances and means of the two inputs into the variance of the output
|
||||||
let combineVariancesFn = switch op {
|
let combineVariancesFn = switch op {
|
||||||
| #Add => (v1, v2, _, _) => v1 +. v2
|
| #Add => (v1, v2, _, _) => v1 +. v2
|
||||||
| #Subtract => (v1, v2, _, _) => v1 +. v2
|
| #Subtract => (v1, v2, _, _) => v1 +. v2
|
||||||
| #Multiply => (v1, v2, m1, m2) => v1 *. v2 +. v1 *. m2 ** 2. +. v2 *. m1 ** 2.
|
| #Multiply => (v1, v2, m1, m2) => v1 *. v2 +. v1 *. m2 ** 2. +. v2 *. m1 ** 2.
|
||||||
| #Exponentiate => (v1, v2, m1, m2) => v1 *. v2 +. v1 *. m2 ** 2. +. v2 *. m1 ** 2.
|
| #Exponentiate => (v1, v2, m1, m2) => v1 *. v2 +. v1 *. m2 ** 2. +. v2 *. m1 ** 2.
|
||||||
|
| #Logarithm => (v1, v2, m1, m2) => v1 *. v2 +. v1 *. m2 ** 2. +. v2 *. m1 ** 2.
|
||||||
| #Divide => (v1, vInv2, m1, mInv2) => v1 *. vInv2 +. v1 *. mInv2 ** 2. +. vInv2 *. m1 ** 2.
|
| #Divide => (v1, vInv2, m1, mInv2) => v1 *. vInv2 +. v1 *. mInv2 ** 2. +. vInv2 *. m1 ** 2.
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,47 @@
|
||||||
open Distributions
|
open Distributions
|
||||||
|
|
||||||
type t = PointSetTypes.continuousShape
|
type t = PointSetTypes.continuousShape
|
||||||
|
|
||||||
|
module Analysis = {
|
||||||
|
let integrate = (
|
||||||
|
~indefiniteIntegralStepwise=(p, h1) => h1 *. p,
|
||||||
|
~indefiniteIntegralLinear=(p, a, b) => a *. p +. b *. p ** 2.0 /. 2.0,
|
||||||
|
t: t,
|
||||||
|
): float => {
|
||||||
|
let xs = t.xyShape.xs
|
||||||
|
let ys = t.xyShape.ys
|
||||||
|
|
||||||
|
E.A.reducei(xs, 0.0, (acc, _x, i) => {
|
||||||
|
let areaUnderIntegral = // TODO Take this switch statement out of the loop body
|
||||||
|
switch (t.interpolation, i) {
|
||||||
|
| (_, 0) => 0.0
|
||||||
|
| (#Stepwise, _) =>
|
||||||
|
indefiniteIntegralStepwise(xs[i], ys[i - 1]) -.
|
||||||
|
indefiniteIntegralStepwise(xs[i - 1], ys[i - 1])
|
||||||
|
| (#Linear, _) =>
|
||||||
|
let x1 = xs[i - 1]
|
||||||
|
let x2 = xs[i]
|
||||||
|
if x1 == x2 {
|
||||||
|
0.0
|
||||||
|
} else {
|
||||||
|
let h1 = ys[i - 1]
|
||||||
|
let h2 = ys[i]
|
||||||
|
let b = (h1 -. h2) /. (x1 -. x2)
|
||||||
|
let a = h1 -. b *. x1
|
||||||
|
indefiniteIntegralLinear(x2, a, b) -. indefiniteIntegralLinear(x1, a, b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
acc +. areaUnderIntegral
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let getMeanOfSquares = (t: t) => {
|
||||||
|
let indefiniteIntegralLinear = (p, a, b) => a *. p ** 3.0 /. 3.0 +. b *. p ** 4.0 /. 4.0
|
||||||
|
let indefiniteIntegralStepwise = (p, h1) => h1 *. p ** 3.0 /. 3.0
|
||||||
|
integrate(~indefiniteIntegralStepwise, ~indefiniteIntegralLinear, t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let getShape = (t: t) => t.xyShape
|
let getShape = (t: t) => t.xyShape
|
||||||
let interpolation = (t: t) => t.interpolation
|
let interpolation = (t: t) => t.interpolation
|
||||||
let make = (~interpolation=#Linear, ~integralSumCache=None, ~integralCache=None, xyShape): t => {
|
let make = (~interpolation=#Linear, ~integralSumCache=None, ~integralCache=None, xyShape): t => {
|
||||||
|
@ -194,7 +235,7 @@ module T = Dist({
|
||||||
let indefiniteIntegralStepwise = (p, h1) => h1 *. p ** 2.0 /. 2.0
|
let indefiniteIntegralStepwise = (p, h1) => h1 *. p ** 2.0 /. 2.0
|
||||||
let indefiniteIntegralLinear = (p, a, b) => a *. p ** 2.0 /. 2.0 +. b *. p ** 3.0 /. 3.0
|
let indefiniteIntegralLinear = (p, a, b) => a *. p ** 2.0 /. 2.0 +. b *. p ** 3.0 /. 3.0
|
||||||
|
|
||||||
XYShape.Analysis.integrateContinuousShape(
|
Analysis.integrate(
|
||||||
~indefiniteIntegralStepwise,
|
~indefiniteIntegralStepwise,
|
||||||
~indefiniteIntegralLinear,
|
~indefiniteIntegralLinear,
|
||||||
t,
|
t,
|
||||||
|
@ -204,7 +245,7 @@ module T = Dist({
|
||||||
XYShape.Analysis.getVarianceDangerously(
|
XYShape.Analysis.getVarianceDangerously(
|
||||||
t,
|
t,
|
||||||
mean,
|
mean,
|
||||||
XYShape.Analysis.getMeanOfSquaresContinuousShape,
|
Analysis.getMeanOfSquares,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -209,8 +209,9 @@ module T = Dist({
|
||||||
let s = getShape(t)
|
let s = getShape(t)
|
||||||
E.A.reducei(s.xs, 0.0, (acc, x, i) => acc +. x *. s.ys[i])
|
E.A.reducei(s.xs, 0.0, (acc, x, i) => acc +. x *. s.ys[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
let variance = (t: t): float => {
|
let variance = (t: t): float => {
|
||||||
let getMeanOfSquares = t => t |> shapeMap(XYShape.Analysis.squareXYShape) |> mean
|
let getMeanOfSquares = t => t |> shapeMap(XYShape.T.square) |> mean
|
||||||
XYShape.Analysis.getVarianceDangerously(t, mean, getMeanOfSquares)
|
XYShape.Analysis.getVarianceDangerously(t, mean, getMeanOfSquares)
|
||||||
}
|
}
|
||||||
})
|
})
|
|
@ -213,8 +213,8 @@ module T = Dist({
|
||||||
|
|
||||||
let getMeanOfSquares = ({discrete, continuous}: t) => {
|
let getMeanOfSquares = ({discrete, continuous}: t) => {
|
||||||
let discreteMean =
|
let discreteMean =
|
||||||
discrete |> Discrete.shapeMap(XYShape.Analysis.squareXYShape) |> Discrete.T.mean
|
discrete |> Discrete.shapeMap(XYShape.T.square) |> Discrete.T.mean
|
||||||
let continuousMean = continuous |> XYShape.Analysis.getMeanOfSquaresContinuousShape
|
let continuousMean = continuous |> Continuous.Analysis.getMeanOfSquares
|
||||||
(discreteMean *. discreteIntegralSum +. continuousMean *. continuousIntegralSum) /.
|
(discreteMean *. discreteIntegralSum +. continuousMean *. continuousIntegralSum) /.
|
||||||
totalIntegralSum
|
totalIntegralSum
|
||||||
}
|
}
|
|
@ -0,0 +1,93 @@
|
||||||
|
type domainLimit = {
|
||||||
|
xPoint: float,
|
||||||
|
excludingProbabilityMass: float,
|
||||||
|
}
|
||||||
|
|
||||||
|
type domain =
|
||||||
|
| Complete
|
||||||
|
| LeftLimited(domainLimit)
|
||||||
|
| RightLimited(domainLimit)
|
||||||
|
| LeftAndRightLimited(domainLimit, domainLimit)
|
||||||
|
|
||||||
|
type distributionType = [
|
||||||
|
| #PDF
|
||||||
|
| #CDF
|
||||||
|
]
|
||||||
|
|
||||||
|
type xyShape = XYShape.xyShape;
|
||||||
|
type interpolationStrategy = XYShape.interpolationStrategy;
|
||||||
|
type extrapolationStrategy = XYShape.extrapolationStrategy;
|
||||||
|
type interpolator = XYShape.extrapolationStrategy;
|
||||||
|
|
||||||
|
type rec continuousShape = {
|
||||||
|
xyShape: xyShape,
|
||||||
|
interpolation: interpolationStrategy,
|
||||||
|
integralSumCache: option<float>,
|
||||||
|
integralCache: option<continuousShape>,
|
||||||
|
}
|
||||||
|
|
||||||
|
type discreteShape = {
|
||||||
|
xyShape: xyShape,
|
||||||
|
integralSumCache: option<float>,
|
||||||
|
integralCache: option<continuousShape>,
|
||||||
|
}
|
||||||
|
|
||||||
|
type mixedShape = {
|
||||||
|
continuous: continuousShape,
|
||||||
|
discrete: discreteShape,
|
||||||
|
integralSumCache: option<float>,
|
||||||
|
integralCache: option<continuousShape>,
|
||||||
|
}
|
||||||
|
|
||||||
|
type pointSetDistMonad<'a, 'b, 'c> =
|
||||||
|
| Mixed('a)
|
||||||
|
| Discrete('b)
|
||||||
|
| Continuous('c)
|
||||||
|
|
||||||
|
@genType
|
||||||
|
type pointSetDist = pointSetDistMonad<mixedShape, discreteShape, continuousShape>
|
||||||
|
|
||||||
|
module ShapeMonad = {
|
||||||
|
let fmap = (t: pointSetDistMonad<'a, 'b, 'c>, (fn1, fn2, fn3)): pointSetDistMonad<'d, 'e, 'f> =>
|
||||||
|
switch t {
|
||||||
|
| Mixed(m) => Mixed(fn1(m))
|
||||||
|
| Discrete(m) => Discrete(fn2(m))
|
||||||
|
| Continuous(m) => Continuous(fn3(m))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type generationSource =
|
||||||
|
| SquiggleString(string)
|
||||||
|
| Shape(pointSetDist)
|
||||||
|
|
||||||
|
@genType
|
||||||
|
type distPlus = {
|
||||||
|
pointSetDist: pointSetDist,
|
||||||
|
integralCache: continuousShape,
|
||||||
|
squiggleString: option<string>,
|
||||||
|
}
|
||||||
|
|
||||||
|
type mixedPoint = {
|
||||||
|
continuous: float,
|
||||||
|
discrete: float,
|
||||||
|
}
|
||||||
|
|
||||||
|
module MixedPoint = {
|
||||||
|
type t = mixedPoint
|
||||||
|
let toContinuousValue = (t: t) => t.continuous
|
||||||
|
let toDiscreteValue = (t: t) => t.discrete
|
||||||
|
let makeContinuous = (continuous: float): t => {continuous: continuous, discrete: 0.0}
|
||||||
|
let makeDiscrete = (discrete: float): t => {continuous: 0.0, discrete: discrete}
|
||||||
|
|
||||||
|
let fmap = (fn: float => float, t: t) => {
|
||||||
|
continuous: fn(t.continuous),
|
||||||
|
discrete: fn(t.discrete),
|
||||||
|
}
|
||||||
|
|
||||||
|
let combine2 = (fn, c: t, d: t): t => {
|
||||||
|
continuous: fn(c.continuous, d.continuous),
|
||||||
|
discrete: fn(c.discrete, d.discrete),
|
||||||
|
}
|
||||||
|
|
||||||
|
let add = combine2((a, b) => a +. b)
|
||||||
|
}
|
|
@ -8,28 +8,22 @@ let make =
|
||||||
(
|
(
|
||||||
~pointSetDist,
|
~pointSetDist,
|
||||||
~squiggleString,
|
~squiggleString,
|
||||||
~domain=Complete,
|
|
||||||
~unit=UnspecifiedDistribution,
|
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
: t => {
|
: t => {
|
||||||
let integral = pointSetDistIntegral(pointSetDist);
|
let integral = pointSetDistIntegral(pointSetDist);
|
||||||
{pointSetDist, domain, integralCache: integral, unit, squiggleString};
|
{pointSetDist, integralCache: integral, squiggleString};
|
||||||
};
|
};
|
||||||
|
|
||||||
let update =
|
let update =
|
||||||
(
|
(
|
||||||
~pointSetDist=?,
|
~pointSetDist=?,
|
||||||
~integralCache=?,
|
~integralCache=?,
|
||||||
~domain=?,
|
|
||||||
~unit=?,
|
|
||||||
~squiggleString=?,
|
~squiggleString=?,
|
||||||
t: t,
|
t: t,
|
||||||
) => {
|
) => {
|
||||||
pointSetDist: E.O.default(t.pointSetDist, pointSetDist),
|
pointSetDist: E.O.default(t.pointSetDist, pointSetDist),
|
||||||
integralCache: E.O.default(t.integralCache, integralCache),
|
integralCache: E.O.default(t.integralCache, integralCache),
|
||||||
domain: E.O.default(t.domain, domain),
|
|
||||||
unit: E.O.default(t.unit, unit),
|
|
||||||
squiggleString: E.O.default(t.squiggleString, squiggleString),
|
squiggleString: E.O.default(t.squiggleString, squiggleString),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -38,12 +32,6 @@ let updateShape = (pointSetDist, t) => {
|
||||||
update(~pointSetDist, ~integralCache, t);
|
update(~pointSetDist, ~integralCache, t);
|
||||||
};
|
};
|
||||||
|
|
||||||
let domainIncludedProbabilityMass = (t: t) =>
|
|
||||||
Domain.includedProbabilityMass(t.domain);
|
|
||||||
|
|
||||||
let domainIncludedProbabilityMassAdjustment = (t: t, f) =>
|
|
||||||
f *. Domain.includedProbabilityMass(t.domain);
|
|
||||||
|
|
||||||
let toPointSetDist = ({pointSetDist, _}: t) => pointSetDist;
|
let toPointSetDist = ({pointSetDist, _}: t) => pointSetDist;
|
||||||
|
|
||||||
let pointSetDistFn = (fn, {pointSetDist}: t) => fn(pointSetDist);
|
let pointSetDistFn = (fn, {pointSetDist}: t) => fn(pointSetDist);
|
||||||
|
@ -73,8 +61,7 @@ module T =
|
||||||
let xToY = (f, t: t) =>
|
let xToY = (f, t: t) =>
|
||||||
t
|
t
|
||||||
|> toPointSetDist
|
|> toPointSetDist
|
||||||
|> PointSetDist.T.xToY(f)
|
|> PointSetDist.T.xToY(f);
|
||||||
|> MixedPoint.fmap(domainIncludedProbabilityMassAdjustment(t));
|
|
||||||
|
|
||||||
let minX = pointSetDistFn(PointSetDist.T.minX);
|
let minX = pointSetDistFn(PointSetDist.T.minX);
|
||||||
let maxX = pointSetDistFn(PointSetDist.T.maxX);
|
let maxX = pointSetDistFn(PointSetDist.T.maxX);
|
||||||
|
@ -115,7 +102,6 @@ module T =
|
||||||
f,
|
f,
|
||||||
toPointSetDist(t),
|
toPointSetDist(t),
|
||||||
)
|
)
|
||||||
|> domainIncludedProbabilityMassAdjustment(t);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: This part is broken when there is a limit, if this is supposed to be taken into account.
|
// TODO: This part is broken when there is a limit, if this is supposed to be taken into account.
|
|
@ -1,7 +1,7 @@
|
||||||
module ExpressionValue = ReducerInterface_ExpressionValue
|
module ExpressionValue = ReducerInterface_ExpressionValue
|
||||||
type expressionValue = ReducerInterface_ExpressionValue.expressionValue
|
type expressionValue = ReducerInterface_ExpressionValue.expressionValue
|
||||||
|
|
||||||
let runGenericOperation = GenericDist_GenericOperation.run(
|
let runGenericOperation = DistributionOperation.run(
|
||||||
~env={
|
~env={
|
||||||
sampleCount: 1000,
|
sampleCount: 1000,
|
||||||
xyPointLength: 1000,
|
xyPointLength: 1000,
|
||||||
|
@ -86,7 +86,7 @@ module SymbolicConstructors = {
|
||||||
|
|
||||||
let symbolicResultToOutput = (
|
let symbolicResultToOutput = (
|
||||||
symbolicResult: result<SymbolicDistTypes.symbolicDist, string>,
|
symbolicResult: result<SymbolicDistTypes.symbolicDist, string>,
|
||||||
): option<GenericDist_GenericOperation.outputType> =>
|
): option<DistributionOperation.outputType> =>
|
||||||
switch symbolicResult {
|
switch symbolicResult {
|
||||||
| Ok(r) => Some(Dist(Symbolic(r)))
|
| Ok(r) => Some(Dist(Symbolic(r)))
|
||||||
| Error(r) => Some(GenDistError(Other(r)))
|
| Error(r) => Some(GenDistError(Other(r)))
|
||||||
|
@ -98,7 +98,7 @@ module Math = {
|
||||||
}
|
}
|
||||||
|
|
||||||
let dispatchToGenericOutput = (call: ExpressionValue.functionCall): option<
|
let dispatchToGenericOutput = (call: ExpressionValue.functionCall): option<
|
||||||
GenericDist_GenericOperation.outputType,
|
DistributionOperation.outputType,
|
||||||
> => {
|
> => {
|
||||||
let (fnName, args) = call
|
let (fnName, args) = call
|
||||||
switch (fnName, args) {
|
switch (fnName, args) {
|
||||||
|
@ -165,7 +165,7 @@ let dispatchToGenericOutput = (call: ExpressionValue.functionCall): option<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let genericOutputToReducerValue = (o: GenericDist_GenericOperation.outputType): result<
|
let genericOutputToReducerValue = (o: DistributionOperation.outputType): result<
|
||||||
expressionValue,
|
expressionValue,
|
||||||
Reducer_ErrorValue.errorValue,
|
Reducer_ErrorValue.errorValue,
|
||||||
> =>
|
> =>
|
||||||
|
|
|
@ -1,4 +1,22 @@
|
||||||
open PointSetTypes
|
@genType
|
||||||
|
type xyShape = {
|
||||||
|
xs: array<float>,
|
||||||
|
ys: array<float>,
|
||||||
|
}
|
||||||
|
|
||||||
|
@genType
|
||||||
|
type interpolationStrategy = [
|
||||||
|
| #Stepwise
|
||||||
|
| #Linear
|
||||||
|
]
|
||||||
|
|
||||||
|
@genType
|
||||||
|
type extrapolationStrategy = [
|
||||||
|
| #UseZero
|
||||||
|
| #UseOutermostPoints
|
||||||
|
]
|
||||||
|
|
||||||
|
type interpolator = (xyShape, int, float) => float
|
||||||
|
|
||||||
let interpolate = (xMin: float, xMax: float, yMin: float, yMax: float, xIntended: float): float => {
|
let interpolate = (xMin: float, xMax: float, yMin: float, yMax: float, xIntended: float): float => {
|
||||||
let minProportion = (xMax -. xIntended) /. (xMax -. xMin)
|
let minProportion = (xMax -. xIntended) /. (xMax -. xMin)
|
||||||
|
@ -25,6 +43,7 @@ module T = {
|
||||||
let xTotalRange = (t: t) => maxX(t) -. minX(t)
|
let xTotalRange = (t: t) => maxX(t) -. minX(t)
|
||||||
let mapX = (fn, t: t): t => {xs: E.A.fmap(fn, t.xs), ys: t.ys}
|
let mapX = (fn, t: t): t => {xs: E.A.fmap(fn, t.xs), ys: t.ys}
|
||||||
let mapY = (fn, t: t): t => {xs: t.xs, ys: E.A.fmap(fn, t.ys)}
|
let mapY = (fn, t: t): t => {xs: t.xs, ys: E.A.fmap(fn, t.ys)}
|
||||||
|
let square = mapX(x => x ** 2.0)
|
||||||
let zip = ({xs, ys}: t) => Belt.Array.zip(xs, ys)
|
let zip = ({xs, ys}: t) => Belt.Array.zip(xs, ys)
|
||||||
let fromArray = ((xs, ys)): t => {xs: xs, ys: ys}
|
let fromArray = ((xs, ys)): t => {xs: xs, ys: ys}
|
||||||
let fromArrays = (xs, ys): t => {xs: xs, ys: ys}
|
let fromArrays = (xs, ys): t => {xs: xs, ys: ys}
|
||||||
|
@ -126,8 +145,8 @@ module XtoY = {
|
||||||
/* Returns a between-points-interpolating function that can be used with PointwiseCombination.combine.
|
/* Returns a between-points-interpolating function that can be used with PointwiseCombination.combine.
|
||||||
Interpolation can either be stepwise (using the value on the left) or linear. Extrapolation can be `UseZero or `UseOutermostPoints. */
|
Interpolation can either be stepwise (using the value on the left) or linear. Extrapolation can be `UseZero or `UseOutermostPoints. */
|
||||||
let continuousInterpolator = (
|
let continuousInterpolator = (
|
||||||
interpolation: PointSetTypes.interpolationStrategy,
|
interpolation: interpolationStrategy,
|
||||||
extrapolation: PointSetTypes.extrapolationStrategy,
|
extrapolation: extrapolationStrategy,
|
||||||
): interpolator =>
|
): interpolator =>
|
||||||
switch (interpolation, extrapolation) {
|
switch (interpolation, extrapolation) {
|
||||||
| (#Linear, #UseZero) =>
|
| (#Linear, #UseZero) =>
|
||||||
|
@ -392,49 +411,9 @@ let logScorePoint = (sampleCount, t1, t2) =>
|
||||||
|> E.O.fmap(Pairs.y)
|
|> E.O.fmap(Pairs.y)
|
||||||
|
|
||||||
module Analysis = {
|
module Analysis = {
|
||||||
let integrateContinuousShape = (
|
|
||||||
~indefiniteIntegralStepwise=(p, h1) => h1 *. p,
|
|
||||||
~indefiniteIntegralLinear=(p, a, b) => a *. p +. b *. p ** 2.0 /. 2.0,
|
|
||||||
t: PointSetTypes.continuousShape,
|
|
||||||
): float => {
|
|
||||||
let xs = t.xyShape.xs
|
|
||||||
let ys = t.xyShape.ys
|
|
||||||
|
|
||||||
E.A.reducei(xs, 0.0, (acc, _x, i) => {
|
|
||||||
let areaUnderIntegral = // TODO Take this switch statement out of the loop body
|
|
||||||
switch (t.interpolation, i) {
|
|
||||||
| (_, 0) => 0.0
|
|
||||||
| (#Stepwise, _) =>
|
|
||||||
indefiniteIntegralStepwise(xs[i], ys[i - 1]) -.
|
|
||||||
indefiniteIntegralStepwise(xs[i - 1], ys[i - 1])
|
|
||||||
| (#Linear, _) =>
|
|
||||||
let x1 = xs[i - 1]
|
|
||||||
let x2 = xs[i]
|
|
||||||
if x1 == x2 {
|
|
||||||
0.0
|
|
||||||
} else {
|
|
||||||
let h1 = ys[i - 1]
|
|
||||||
let h2 = ys[i]
|
|
||||||
let b = (h1 -. h2) /. (x1 -. x2)
|
|
||||||
let a = h1 -. b *. x1
|
|
||||||
indefiniteIntegralLinear(x2, a, b) -. indefiniteIntegralLinear(x1, a, b)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
acc +. areaUnderIntegral
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
let getMeanOfSquaresContinuousShape = (t: PointSetTypes.continuousShape) => {
|
|
||||||
let indefiniteIntegralLinear = (p, a, b) => a *. p ** 3.0 /. 3.0 +. b *. p ** 4.0 /. 4.0
|
|
||||||
let indefiniteIntegralStepwise = (p, h1) => h1 *. p ** 3.0 /. 3.0
|
|
||||||
integrateContinuousShape(~indefiniteIntegralStepwise, ~indefiniteIntegralLinear, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
let getVarianceDangerously = (t: 't, mean: 't => float, getMeanOfSquares: 't => float): float => {
|
let getVarianceDangerously = (t: 't, mean: 't => float, getMeanOfSquares: 't => float): float => {
|
||||||
let meanSquared = mean(t) ** 2.0
|
let meanSquared = mean(t) ** 2.0
|
||||||
let meanOfSquares = getMeanOfSquares(t)
|
let meanOfSquares = getMeanOfSquares(t)
|
||||||
meanOfSquares -. meanSquared
|
meanOfSquares -. meanSquared
|
||||||
}
|
}
|
||||||
|
|
||||||
let squareXYShape = T.mapX(x => x ** 2.0)
|
|
||||||
}
|
}
|
|
@ -1,154 +0,0 @@
|
||||||
type domainLimit = {
|
|
||||||
xPoint: float,
|
|
||||||
excludingProbabilityMass: float,
|
|
||||||
}
|
|
||||||
|
|
||||||
type domain =
|
|
||||||
| Complete
|
|
||||||
| LeftLimited(domainLimit)
|
|
||||||
| RightLimited(domainLimit)
|
|
||||||
| LeftAndRightLimited(domainLimit, domainLimit)
|
|
||||||
|
|
||||||
type distributionType = [
|
|
||||||
| #PDF
|
|
||||||
| #CDF
|
|
||||||
]
|
|
||||||
|
|
||||||
type xyShape = {
|
|
||||||
xs: array<float>,
|
|
||||||
ys: array<float>,
|
|
||||||
}
|
|
||||||
|
|
||||||
type interpolationStrategy = [
|
|
||||||
| #Stepwise
|
|
||||||
| #Linear
|
|
||||||
]
|
|
||||||
type extrapolationStrategy = [
|
|
||||||
| #UseZero
|
|
||||||
| #UseOutermostPoints
|
|
||||||
]
|
|
||||||
|
|
||||||
type interpolator = (xyShape, int, float) => float
|
|
||||||
|
|
||||||
type rec continuousShape = {
|
|
||||||
xyShape: xyShape,
|
|
||||||
interpolation: interpolationStrategy,
|
|
||||||
integralSumCache: option<float>,
|
|
||||||
integralCache: option<continuousShape>,
|
|
||||||
}
|
|
||||||
|
|
||||||
type discreteShape = {
|
|
||||||
xyShape: xyShape,
|
|
||||||
integralSumCache: option<float>,
|
|
||||||
integralCache: option<continuousShape>,
|
|
||||||
}
|
|
||||||
|
|
||||||
type mixedShape = {
|
|
||||||
continuous: continuousShape,
|
|
||||||
discrete: discreteShape,
|
|
||||||
integralSumCache: option<float>,
|
|
||||||
integralCache: option<continuousShape>,
|
|
||||||
}
|
|
||||||
|
|
||||||
type pointSetDistMonad<'a, 'b, 'c> =
|
|
||||||
| Mixed('a)
|
|
||||||
| Discrete('b)
|
|
||||||
| Continuous('c)
|
|
||||||
|
|
||||||
@genType
|
|
||||||
type pointSetDist = pointSetDistMonad<mixedShape, discreteShape, continuousShape>
|
|
||||||
|
|
||||||
module ShapeMonad = {
|
|
||||||
let fmap = (t: pointSetDistMonad<'a, 'b, 'c>, (fn1, fn2, fn3)): pointSetDistMonad<'d, 'e, 'f> =>
|
|
||||||
switch t {
|
|
||||||
| Mixed(m) => Mixed(fn1(m))
|
|
||||||
| Discrete(m) => Discrete(fn2(m))
|
|
||||||
| Continuous(m) => Continuous(fn3(m))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type generationSource =
|
|
||||||
| SquiggleString(string)
|
|
||||||
| Shape(pointSetDist)
|
|
||||||
|
|
||||||
type distributionUnit =
|
|
||||||
| UnspecifiedDistribution
|
|
||||||
|
|
||||||
@genType
|
|
||||||
type distPlus = {
|
|
||||||
pointSetDist: pointSetDist,
|
|
||||||
domain: domain,
|
|
||||||
integralCache: continuousShape,
|
|
||||||
unit: distributionUnit,
|
|
||||||
squiggleString: option<string>,
|
|
||||||
}
|
|
||||||
|
|
||||||
module DistributionUnit = {
|
|
||||||
let toJson = (distributionUnit: distributionUnit) =>
|
|
||||||
switch distributionUnit {
|
|
||||||
| _ => Js.Null.fromOption(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module Domain = {
|
|
||||||
let excludedProbabilityMass = (t: domain) =>
|
|
||||||
switch t {
|
|
||||||
| Complete => 0.0
|
|
||||||
| LeftLimited({excludingProbabilityMass}) => excludingProbabilityMass
|
|
||||||
| RightLimited({excludingProbabilityMass}) => excludingProbabilityMass
|
|
||||||
| LeftAndRightLimited({excludingProbabilityMass: l}, {excludingProbabilityMass: r}) => l +. r
|
|
||||||
}
|
|
||||||
|
|
||||||
let includedProbabilityMass = (t: domain) => 1.0 -. excludedProbabilityMass(t)
|
|
||||||
|
|
||||||
let initialProbabilityMass = (t: domain) =>
|
|
||||||
switch t {
|
|
||||||
| Complete
|
|
||||||
| RightLimited(_) => 0.0
|
|
||||||
| LeftLimited({excludingProbabilityMass}) => excludingProbabilityMass
|
|
||||||
| LeftAndRightLimited({excludingProbabilityMass}, _) => excludingProbabilityMass
|
|
||||||
}
|
|
||||||
|
|
||||||
let normalizeProbabilityMass = (t: domain) => 1. /. excludedProbabilityMass(t)
|
|
||||||
|
|
||||||
let yPointToSubYPoint = (t: domain, yPoint) =>
|
|
||||||
switch t {
|
|
||||||
| Complete => Some(yPoint)
|
|
||||||
| LeftLimited({excludingProbabilityMass}) if yPoint < excludingProbabilityMass => None
|
|
||||||
| LeftLimited({excludingProbabilityMass}) if yPoint >= excludingProbabilityMass =>
|
|
||||||
Some((yPoint -. excludingProbabilityMass) /. includedProbabilityMass(t))
|
|
||||||
| RightLimited({excludingProbabilityMass}) if yPoint > 1. -. excludingProbabilityMass => None
|
|
||||||
| RightLimited({excludingProbabilityMass}) if yPoint <= 1. -. excludingProbabilityMass =>
|
|
||||||
Some(yPoint /. includedProbabilityMass(t))
|
|
||||||
| LeftAndRightLimited({excludingProbabilityMass: l}, _) if yPoint < l => None
|
|
||||||
| LeftAndRightLimited(_, {excludingProbabilityMass: r}) if yPoint > 1.0 -. r => None
|
|
||||||
| LeftAndRightLimited({excludingProbabilityMass: l}, _) =>
|
|
||||||
Some((yPoint -. l) /. includedProbabilityMass(t))
|
|
||||||
| _ => None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type mixedPoint = {
|
|
||||||
continuous: float,
|
|
||||||
discrete: float,
|
|
||||||
}
|
|
||||||
|
|
||||||
module MixedPoint = {
|
|
||||||
type t = mixedPoint
|
|
||||||
let toContinuousValue = (t: t) => t.continuous
|
|
||||||
let toDiscreteValue = (t: t) => t.discrete
|
|
||||||
let makeContinuous = (continuous: float): t => {continuous: continuous, discrete: 0.0}
|
|
||||||
let makeDiscrete = (discrete: float): t => {continuous: 0.0, discrete: discrete}
|
|
||||||
|
|
||||||
let fmap = (fn: float => float, t: t) => {
|
|
||||||
continuous: fn(t.continuous),
|
|
||||||
discrete: fn(t.discrete),
|
|
||||||
}
|
|
||||||
|
|
||||||
let combine2 = (fn, c: t, d: t): t => {
|
|
||||||
continuous: fn(c.continuous, d.continuous),
|
|
||||||
discrete: fn(c.discrete, d.discrete),
|
|
||||||
}
|
|
||||||
|
|
||||||
let add = combine2((a, b) => a +. b)
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user