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 Expect
|
||||
|
||||
let env: GenericDist_GenericOperation.env = {
|
||||
let env: DistributionOperation.env = {
|
||||
sampleCount: 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 uniformDist: GenericDist_Types.genericDist = Symbolic(#Uniform({low: 9.0, high: 10.0}))
|
||||
|
||||
let {toFloat, toDist, toString, toError} = module(GenericDist_GenericOperation.Output)
|
||||
let {run} = module(GenericDist_GenericOperation)
|
||||
let {fmap} = module(GenericDist_GenericOperation.Output)
|
||||
let {toFloat, toDist, toString, toError} = module(DistributionOperation.Output)
|
||||
let {run} = module(DistributionOperation)
|
||||
let {fmap} = module(DistributionOperation.Output)
|
||||
let run = run(~env)
|
||||
let outputMap = fmap(~env)
|
||||
let toExt: option<'a> => 'a = E.O.toExt(
|
||||
|
@ -29,7 +29,7 @@ describe("normalize", () => {
|
|||
|
||||
describe("mean", () => {
|
||||
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))
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import {runAll} 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 {t as DistPlus} from '../rescript/pointSetDist/DistPlus.gen';
|
||||
export type {t as DistPlus} from '../rescript/OldInterpreter/DistPlus.gen';
|
||||
|
||||
export let defaultSamplingInputs : SamplingInputs = {
|
||||
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,
|
||||
~leftCutoff: option<float>=?,
|
||||
~rightCutoff: option<float>=?,
|
||||
unit,
|
||||
unit
|
||||
) => result<t, error>
|
||||
|
||||
let algebraicCombination: (
|
|
@ -118,13 +118,14 @@ let combineShapesContinuousContinuous = (
|
|||
| #Logarithm => (m1, m2) => log(m1) /. log(m2)
|
||||
} // 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
|
||||
let combineVariancesFn = switch op {
|
||||
| #Add => (v1, v2, _, _) => v1 +. v2
|
||||
| #Subtract => (v1, v2, _, _) => v1 +. v2
|
||||
| #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.
|
||||
| #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.
|
||||
}
|
||||
|
|
@ -1,6 +1,47 @@
|
|||
open Distributions
|
||||
|
||||
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 interpolation = (t: t) => t.interpolation
|
||||
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 indefiniteIntegralLinear = (p, a, b) => a *. p ** 2.0 /. 2.0 +. b *. p ** 3.0 /. 3.0
|
||||
|
||||
XYShape.Analysis.integrateContinuousShape(
|
||||
Analysis.integrate(
|
||||
~indefiniteIntegralStepwise,
|
||||
~indefiniteIntegralLinear,
|
||||
t,
|
||||
|
@ -204,7 +245,7 @@ module T = Dist({
|
|||
XYShape.Analysis.getVarianceDangerously(
|
||||
t,
|
||||
mean,
|
||||
XYShape.Analysis.getMeanOfSquaresContinuousShape,
|
||||
Analysis.getMeanOfSquares,
|
||||
)
|
||||
})
|
||||
|
|
@ -209,8 +209,9 @@ module T = Dist({
|
|||
let s = getShape(t)
|
||||
E.A.reducei(s.xs, 0.0, (acc, x, i) => acc +. x *. s.ys[i])
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
})
|
|
@ -213,8 +213,8 @@ module T = Dist({
|
|||
|
||||
let getMeanOfSquares = ({discrete, continuous}: t) => {
|
||||
let discreteMean =
|
||||
discrete |> Discrete.shapeMap(XYShape.Analysis.squareXYShape) |> Discrete.T.mean
|
||||
let continuousMean = continuous |> XYShape.Analysis.getMeanOfSquaresContinuousShape
|
||||
discrete |> Discrete.shapeMap(XYShape.T.square) |> Discrete.T.mean
|
||||
let continuousMean = continuous |> Continuous.Analysis.getMeanOfSquares
|
||||
(discreteMean *. discreteIntegralSum +. continuousMean *. continuousIntegralSum) /.
|
||||
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,
|
||||
~squiggleString,
|
||||
~domain=Complete,
|
||||
~unit=UnspecifiedDistribution,
|
||||
(),
|
||||
)
|
||||
: t => {
|
||||
let integral = pointSetDistIntegral(pointSetDist);
|
||||
{pointSetDist, domain, integralCache: integral, unit, squiggleString};
|
||||
{pointSetDist, integralCache: integral, squiggleString};
|
||||
};
|
||||
|
||||
let update =
|
||||
(
|
||||
~pointSetDist=?,
|
||||
~integralCache=?,
|
||||
~domain=?,
|
||||
~unit=?,
|
||||
~squiggleString=?,
|
||||
t: t,
|
||||
) => {
|
||||
pointSetDist: E.O.default(t.pointSetDist, pointSetDist),
|
||||
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),
|
||||
};
|
||||
|
||||
|
@ -38,12 +32,6 @@ let updateShape = (pointSetDist, 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 pointSetDistFn = (fn, {pointSetDist}: t) => fn(pointSetDist);
|
||||
|
@ -73,8 +61,7 @@ module T =
|
|||
let xToY = (f, t: t) =>
|
||||
t
|
||||
|> toPointSetDist
|
||||
|> PointSetDist.T.xToY(f)
|
||||
|> MixedPoint.fmap(domainIncludedProbabilityMassAdjustment(t));
|
||||
|> PointSetDist.T.xToY(f);
|
||||
|
||||
let minX = pointSetDistFn(PointSetDist.T.minX);
|
||||
let maxX = pointSetDistFn(PointSetDist.T.maxX);
|
||||
|
@ -115,7 +102,6 @@ module T =
|
|||
f,
|
||||
toPointSetDist(t),
|
||||
)
|
||||
|> domainIncludedProbabilityMassAdjustment(t);
|
||||
};
|
||||
|
||||
// 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
|
||||
type expressionValue = ReducerInterface_ExpressionValue.expressionValue
|
||||
|
||||
let runGenericOperation = GenericDist_GenericOperation.run(
|
||||
let runGenericOperation = DistributionOperation.run(
|
||||
~env={
|
||||
sampleCount: 1000,
|
||||
xyPointLength: 1000,
|
||||
|
@ -86,7 +86,7 @@ module SymbolicConstructors = {
|
|||
|
||||
let symbolicResultToOutput = (
|
||||
symbolicResult: result<SymbolicDistTypes.symbolicDist, string>,
|
||||
): option<GenericDist_GenericOperation.outputType> =>
|
||||
): option<DistributionOperation.outputType> =>
|
||||
switch symbolicResult {
|
||||
| Ok(r) => Some(Dist(Symbolic(r)))
|
||||
| Error(r) => Some(GenDistError(Other(r)))
|
||||
|
@ -98,7 +98,7 @@ module Math = {
|
|||
}
|
||||
|
||||
let dispatchToGenericOutput = (call: ExpressionValue.functionCall): option<
|
||||
GenericDist_GenericOperation.outputType,
|
||||
DistributionOperation.outputType,
|
||||
> => {
|
||||
let (fnName, args) = call
|
||||
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,
|
||||
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 minProportion = (xMax -. xIntended) /. (xMax -. xMin)
|
||||
|
@ -25,6 +43,7 @@ module 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 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 fromArray = ((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.
|
||||
Interpolation can either be stepwise (using the value on the left) or linear. Extrapolation can be `UseZero or `UseOutermostPoints. */
|
||||
let continuousInterpolator = (
|
||||
interpolation: PointSetTypes.interpolationStrategy,
|
||||
extrapolation: PointSetTypes.extrapolationStrategy,
|
||||
interpolation: interpolationStrategy,
|
||||
extrapolation: extrapolationStrategy,
|
||||
): interpolator =>
|
||||
switch (interpolation, extrapolation) {
|
||||
| (#Linear, #UseZero) =>
|
||||
|
@ -392,49 +411,9 @@ let logScorePoint = (sampleCount, t1, t2) =>
|
|||
|> E.O.fmap(Pairs.y)
|
||||
|
||||
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 meanSquared = mean(t) ** 2.0
|
||||
let meanOfSquares = getMeanOfSquares(t)
|
||||
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