Formatting

This commit is contained in:
Nuno Sempere 2020-04-18 23:27:24 +02:00
parent 2f45f92552
commit a89960a1e7
3 changed files with 147 additions and 105 deletions

View File

@ -13,16 +13,15 @@ let makeTest = (~only=false, str, item1, item2) =>
); );
let makeTestCloseEquality = (~only=false, str, item1, item2, ~digits) => let makeTestCloseEquality = (~only=false, str, item1, item2, ~digits) =>
only only
? Only.test(str, () => ? Only.test(str, () =>
expect(item1) |> toBeSoCloseTo(item2, ~digits) expect(item1) |> toBeSoCloseTo(item2, ~digits)
) )
: test(str, () => : test(str, () =>
expect(item1) |> toBeSoCloseTo(item2, ~digits) expect(item1) |> toBeSoCloseTo(item2, ~digits)
); );
describe("Shape", () => { describe("Shape", () => {
describe("Continuous", () => { describe("Continuous", () => {
open Distributions.Continuous; open Distributions.Continuous;
let continuous = make(`Linear, shape); let continuous = make(`Linear, shape);
@ -195,7 +194,13 @@ describe("Shape", () => {
0.9, 0.9,
); );
makeTest("integralEndY", T.Integral.sum(~cache=None, discrete), 1.0); makeTest("integralEndY", T.Integral.sum(~cache=None, discrete), 1.0);
makeTest("mean", T.getMean(discrete), 3.9);
makeTestCloseEquality(
"variance",
T.getVariance(discrete),
5.89,
~digits=7,
);
}); });
describe("Mixed", () => { describe("Mixed", () => {
@ -300,7 +305,6 @@ describe("Shape", () => {
}, },
), ),
); );
}); });
describe("Distplus", () => { describe("Distplus", () => {
@ -380,33 +384,36 @@ describe("Shape", () => {
let stdev = 4.0; let stdev = 4.0;
let variance = stdev ** 2.0; let variance = stdev ** 2.0;
let numSamples = 10000; let numSamples = 10000;
open Distributions.Shape; open Distributions.Shape;
let normal: SymbolicDist.dist = `Normal({ mean, stdev}); let normal: SymbolicDist.dist = `Normal({mean, stdev});
let normalShape = SymbolicDist.GenericSimple.toShape(normal, numSamples); let normalShape = SymbolicDist.GenericSimple.toShape(normal, numSamples);
let lognormal = SymbolicDist.Lognormal.fromMeanAndStdev(mean, stdev); let lognormal = SymbolicDist.Lognormal.fromMeanAndStdev(mean, stdev);
let lognormalShape = SymbolicDist.GenericSimple.toShape(lognormal, numSamples); let lognormalShape =
SymbolicDist.GenericSimple.toShape(lognormal, numSamples);
makeTestCloseEquality( makeTestCloseEquality(
"Mean of a normal", "Mean of a normal",
T.getMean(normalShape), T.getMean(normalShape),
mean, mean,
~digits=2); ~digits=2,
);
makeTestCloseEquality( makeTestCloseEquality(
"Variance of a normal", "Variance of a normal",
T.getVariance(normalShape), T.getVariance(normalShape),
variance, variance,
~digits=1); ~digits=1,
);
makeTestCloseEquality( makeTestCloseEquality(
"Mean of a lognormal", "Mean of a lognormal",
T.getMean(lognormalShape), T.getMean(lognormalShape),
mean, mean,
~digits=2); ~digits=2,
);
makeTestCloseEquality( makeTestCloseEquality(
"Variance of a lognormal", "Variance of a lognormal",
T.getVariance(lognormalShape), T.getVariance(lognormalShape),
variance, variance,
~digits=0); ~digits=0,
);
}); });
}); });

View File

@ -141,8 +141,22 @@ module Continuous = {
let toScaledContinuous = t => Some(t); let toScaledContinuous = t => Some(t);
let toScaledDiscrete = _ => None; let toScaledDiscrete = _ => None;
let getMean = (t: t) => XYShape.Analysis.integrateContinuousShape(t); let getMean = (t: t) => {
let getVariance = (t: t): float => XYShape.Analysis.getVarianceDangerously(t, getMean, XYShape.Analysis.getMeanOfSquaresContinuousShape); 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(
~indefiniteIntegralStepwise,
~indefiniteIntegralLinear,
t,
);
};
let getVariance = (t: t): float =>
XYShape.Analysis.getVarianceDangerously(
t,
getMean,
XYShape.Analysis.getMeanOfSquaresContinuousShape,
);
}); });
}; };
@ -215,13 +229,14 @@ module Discrete = {
|> Continuous.getShape |> Continuous.getShape
|> XYShape.YtoX.linear(f); |> XYShape.YtoX.linear(f);
let getMean = (t: t): float => E.A.reducei(t.xs, 0.0, (acc, x, i) => acc +. x*. t.ys[i]); let getMean = (t: t): float =>
E.A.reducei(t.xs, 0.0, (acc, x, i) => acc +. x *. t.ys[i]);
let getVariance = (t: t): float => { let getVariance = (t: t): float => {
let getMeanOfSquares = t => getMean(XYShape.Analysis.squareXYShape(t)); let getMeanOfSquares = t =>
getMean(XYShape.Analysis.squareXYShape(t));
XYShape.Analysis.getVarianceDangerously(t, getMean, getMeanOfSquares); XYShape.Analysis.getVarianceDangerously(t, getMean, getMeanOfSquares);
}; };
}); });
}; };
// TODO: I think this shouldn't assume continuous/discrete are normalized to 1.0, and thus should not need the discreteProbabilityMassFraction being separate. // TODO: I think this shouldn't assume continuous/discrete are normalized to 1.0, and thus should not need the discreteProbabilityMassFraction being separate.
@ -393,27 +408,38 @@ module Mixed = {
}; };
}; };
let getMean = (t: t) : float => { let getMean = (t: t): float => {
let discreteProbabilityMassFraction = t.discreteProbabilityMassFraction; let discreteProbabilityMassFraction =
let mean = switch(discreteProbabilityMassFraction){ t.discreteProbabilityMassFraction;
| 1.0 => Discrete.T.getMean(t.discrete); switch (discreteProbabilityMassFraction) {
| 0.0 => Continuous.T.getMean(t.continuous); | 1.0 => Discrete.T.getMean(t.discrete)
| _ => (Discrete.T.getMean(t.discrete) *. discreteProbabilityMassFraction) | 0.0 => Continuous.T.getMean(t.continuous)
+. (Continuous.T.getMean(t.continuous) *. (1.0 -. discreteProbabilityMassFraction)) | _ =>
Discrete.T.getMean(t.discrete)
*. discreteProbabilityMassFraction
+. Continuous.T.getMean(t.continuous)
*. (1.0 -. discreteProbabilityMassFraction)
}; };
mean;
}; };
let getVariance = (t: t) : float => { let getVariance = (t: t): float => {
let discreteProbabilityMassFraction = t.discreteProbabilityMassFraction; let discreteProbabilityMassFraction =
t.discreteProbabilityMassFraction;
let getMeanOfSquares = (t: t) => { let getMeanOfSquares = (t: t) => {
Discrete.T.getMean(XYShape.Analysis.squareXYShape(t.discrete))*.t.discreteProbabilityMassFraction Discrete.T.getMean(XYShape.Analysis.squareXYShape(t.discrete))
+. XYShape.Analysis.getMeanOfSquaresContinuousShape(t.continuous)*.(1.0 -. t.discreteProbabilityMassFraction) *. t.discreteProbabilityMassFraction
+. XYShape.Analysis.getMeanOfSquaresContinuousShape(t.continuous)
*. (1.0 -. t.discreteProbabilityMassFraction);
}; };
switch(discreteProbabilityMassFraction){ switch (discreteProbabilityMassFraction) {
| 1.0 => Discrete.T.getVariance(t.discrete); | 1.0 => Discrete.T.getVariance(t.discrete)
| 0.0 => Continuous.T.getVariance(t.continuous); | 0.0 => Continuous.T.getVariance(t.continuous)
| _ => XYShape.Analysis.getVarianceDangerously(t, getMean, getMeanOfSquares); | _ =>
XYShape.Analysis.getVarianceDangerously(
t,
getMean,
getMeanOfSquares,
)
}; };
}; };
}); });
@ -521,17 +547,19 @@ module Shape = {
Continuous.T.mapY(fn), Continuous.T.mapY(fn),
)); ));
let getMean = (t: t): float => switch (t) { let getMean = (t: t): float =>
| Mixed(m) => Mixed.T.getMean(m); switch (t) {
| Discrete(m) => Discrete.T.getMean(m); | Mixed(m) => Mixed.T.getMean(m)
| Continuous(m) => Continuous.T.getMean(m); | Discrete(m) => Discrete.T.getMean(m)
}; | Continuous(m) => Continuous.T.getMean(m)
};
let getVariance = (t: t): float => switch (t) { let getVariance = (t: t): float =>
| Mixed(m) => Mixed.T.getVariance(m); switch (t) {
| Discrete(m) => Discrete.T.getVariance(m); | Mixed(m) => Mixed.T.getVariance(m)
| Continuous(m) => Continuous.T.getVariance(m); | Discrete(m) => Discrete.T.getVariance(m)
}; | Continuous(m) => Continuous.T.getVariance(m)
};
}); });
}; };

View File

@ -17,7 +17,7 @@ module T = {
type ts = array(xyShape); type ts = array(xyShape);
let xs = (t: t) => t.xs; let xs = (t: t) => t.xs;
let ys = (t: t) => t.ys; let ys = (t: t) => t.ys;
let empty = ({xs: [||], ys: [||]}); let empty = {xs: [||], ys: [||]};
let minX = (t: t) => t |> xs |> E.A.Sorted.min |> extImp; let minX = (t: t) => t |> xs |> E.A.Sorted.min |> extImp;
let maxX = (t: t) => t |> xs |> E.A.Sorted.max |> extImp; let maxX = (t: t) => t |> xs |> E.A.Sorted.max |> extImp;
let firstY = (t: t) => t |> ys |> E.A.first |> extImp; let firstY = (t: t) => t |> ys |> E.A.first |> extImp;
@ -299,55 +299,62 @@ let logScorePoint = (sampleCount, t1, t2) =>
|> E.O.fmap(Pairs.last) |> E.O.fmap(Pairs.last)
|> E.O.fmap(Pairs.y); |> E.O.fmap(Pairs.y);
module Analysis = { module Analysis = {
let integrateContinuousShape = ( let integrateContinuousShape =
~indefiniteIntegralStepwise = (p,h1) => (h1*.(p**2.0)/. 2.0), (
~indefiniteIntegralLinear = (p, a, b) => (a *. (p ** 2.0) /.2.0) +. (b *. (p**3.0) /. 3.0), ~indefiniteIntegralStepwise=(p, h1) => h1 *. p,
t: DistTypes.continuousShape ~indefiniteIntegralLinear=(p, a, b) => a *. p +. b *. p ** 2.0 /. 2.0,
): float => { t: DistTypes.continuousShape,
)
: float => {
let xs = t.xyShape.xs; let xs = t.xyShape.xs;
let ys = t.xyShape.ys; let ys = t.xyShape.ys;
E.A.reducei(xs, 0.0, (acc, _x, i) => { E.A.reducei(
let areaUnderIntegral = switch(t.interpolation, i){ xs,
| (_, 0) => 0.0; 0.0,
| (`Stepwise, _) => indefiniteIntegralStepwise(xs[i],ys[i-1]) (acc, _x, i) => {
-. indefiniteIntegralStepwise(xs[i-1],ys[i-1]); let areaUnderIntegral =
| (`Linear, _) => { switch (t.interpolation, i) {
let x1 = xs[i-1]; | (_, 0) => 0.0
let x2 = xs[i]; | (`Stepwise, _) =>
let h1 = ys[i-1]; indefiniteIntegralStepwise(xs[i], ys[i - 1])
let h2 = ys[i]; -. indefiniteIntegralStepwise(xs[i - 1], ys[i - 1])
let b = (h1 -. h2 ) /. (x1 -.x2) | (`Linear, _) =>
let a = h1 -. b *.x1; let x1 = xs[i - 1];
indefiniteIntegralLinear(x2, a, b) -. indefiniteIntegralLinear(x1, a, b); let x2 = xs[i];
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;
acc +. areaUnderIntegral; },
}); );
}; };
let getVarianceDangerously = (
t: 't,
getMean: ('t => float),
getMeanOfSquares: ('t => float),
): float => {
let meanSquared = getMean(t)**2.0;
let meanOfSquares = getMeanOfSquares(t);
meanOfSquares -. meanSquared;
};
let squareXYShape = t: DistTypes.xyShape => {...t, xs: E.A.fmap(x => x**2.0, t.xs)};
let getMeanOfSquaresContinuousShape = (t: DistTypes.continuousShape) => { let getMeanOfSquaresContinuousShape = (t: DistTypes.continuousShape) => {
let indefiniteIntegralLinear = (p, a, b) => (a *. (p ** 3.0) /.3.0) +. (b *. (p**4.0) /. 4.0); let indefiniteIntegralLinear = (p, a, b) =>
let indefiniteIntegralStepwise = (p,h1) => h1*.(p**3.0)/. 3.0; a *. p ** 3.0 /. 3.0 +. b *. p ** 4.0 /. 4.0;
let indefiniteIntegralStepwise = (p, h1) => h1 *. p ** 3.0 /. 3.0;
integrateContinuousShape( integrateContinuousShape(
~indefiniteIntegralStepwise, ~indefiniteIntegralStepwise,
~indefiniteIntegralLinear, ~indefiniteIntegralLinear,
t t,
); );
} };
let getVarianceDangerously =
(t: 't, getMean: 't => float, getMeanOfSquares: 't => float): float => {
let meanSquared = getMean(t) ** 2.0;
let meanOfSquares = getMeanOfSquares(t);
meanOfSquares -. meanSquared;
};
let squareXYShape = (t): DistTypes.xyShape => {
...t,
xs: E.A.fmap(x => x ** 2.0, t.xs),
};
}; };