Fix rendering of uniforms; add normalization constant in convolution code

This commit is contained in:
Sebastian Kosch 2020-07-06 23:43:25 -07:00
parent 89e07dad86
commit 8d09cf9beb
5 changed files with 34 additions and 29 deletions

View File

@ -146,7 +146,6 @@ module DemoDist = {
(), (),
); );
let response = DistPlusRenderer.run(inputs); let response = DistPlusRenderer.run(inputs);
Js.log(response);
switch (RenderTypes.DistPlusRenderer.Outputs.distplus(response)) { switch (RenderTypes.DistPlusRenderer.Outputs.distplus(response)) {
| Some(distPlus) => <DistPlusPlot distPlus /> | Some(distPlus) => <DistPlusPlot distPlus />
| _ => | _ =>
@ -172,7 +171,7 @@ let make = () => {
~onSubmit=({state}) => {None}, ~onSubmit=({state}) => {None},
~initialState={ ~initialState={
//guesstimatorString: "mm(normal(-10, 2), uniform(18, 25), lognormal({mean: 10, stdev: 8}), triangular(31,40,50))", //guesstimatorString: "mm(normal(-10, 2), uniform(18, 25), lognormal({mean: 10, stdev: 8}), triangular(31,40,50))",
guesstimatorString: "truncate(normal(100, 60), 50, 100)", guesstimatorString: "uniform(1,2) * uniform(2, 3)", // , triangular(30, 40, 60)
domainType: "Complete", domainType: "Complete",
xPoint: "50.0", xPoint: "50.0",
xPoint2: "60.0", xPoint2: "60.0",

View File

@ -139,8 +139,8 @@ let combineShapesContinuousContinuous =
// 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 = let combineVariancesFn =
switch (op) { switch (op) {
| `Add => ((v1, v2, m1, m2) => v1 +. v2) | `Add => ((v1, v2, _, _) => v1 +. v2)
| `Subtract => ((v1, v2, m1, m2) => v1 +. v2) | `Subtract => ((v1, v2, _, _) => v1 +. v2)
| `Multiply => ( | `Multiply => (
(v1, v2, m1, m2) => v1 *. v2 +. v1 *. m2 ** 2. +. v2 *. m1 ** 2. (v1, v2, m1, m2) => v1 *. v2 +. v1 *. m2 ** 2. +. v2 *. m1 ** 2.
) )
@ -176,8 +176,8 @@ let combineShapesContinuousContinuous =
let _ = Belt.Array.set(means, k, mean); let _ = Belt.Array.set(means, k, mean);
let _ = Belt.Array.set(variances, k, variance); let _ = Belt.Array.set(variances, k, variance);
// update bounds // update bounds
let minX = mean -. variance *. 1.644854; let minX = mean -. 2. *. sqrt(variance) *. 1.644854;
let maxX = mean +. variance *. 1.644854; let maxX = mean +. 2. *. sqrt(variance) *. 1.644854;
if (minX < outputMinX^) { if (minX < outputMinX^) {
outputMinX := minX; outputMinX := minX;
}; };
@ -193,11 +193,11 @@ let combineShapesContinuousContinuous =
let outputXs: array(float) = E.A.Floats.range(outputMinX^, outputMaxX^, nOut); let outputXs: array(float) = E.A.Floats.range(outputMinX^, outputMaxX^, nOut);
let outputYs: array(float) = Belt.Array.make(nOut, 0.0); let outputYs: array(float) = Belt.Array.make(nOut, 0.0);
// now, for each of the outputYs, accumulate from a Gaussian kernel over each input point. // now, for each of the outputYs, accumulate from a Gaussian kernel over each input point.
for (j in 0 to E.A.length(masses) - 1) { for (j in 0 to E.A.length(masses) - 1) { // go through all of the result points
let _ = if (variances[j] > 0.) { let _ = if (variances[j] > 0. && masses[j] > 0.) {
for (i in 0 to E.A.length(outputXs) - 1) { for (i in 0 to E.A.length(outputXs) - 1) { // go through all of the target points
let dx = outputXs[i] -. means[j]; let dx = outputXs[i] -. means[j];
let contribution = masses[j] *. exp(-. (dx ** 2.) /. (2. *. variances[j])); let contribution = masses[j] *. exp(-. (dx ** 2.) /. (2. *. variances[j])) /. (sqrt(2. *. 3.14159276 *. variances[j]));
let _ = Belt.Array.set(outputYs, i, outputYs[i] +. contribution); let _ = Belt.Array.set(outputYs, i, outputYs[i] +. contribution);
(); ();
}; };

View File

@ -112,7 +112,7 @@ module Continuous = {
t2.knownIntegralSum, t2.knownIntegralSum,
); );
make( let res = make(
`Linear, `Linear,
XYShape.PointwiseCombination.combine( XYShape.PointwiseCombination.combine(
~xsSelection=ALL_XS, ~xsSelection=ALL_XS,
@ -123,6 +123,7 @@ module Continuous = {
), ),
combinedIntegralSum, combinedIntegralSum,
); );
res
}; };
let toLinear = (t: t): option(t) => { let toLinear = (t: t): option(t) => {
@ -219,7 +220,9 @@ module Continuous = {
let integral = (~cache, t) => let integral = (~cache, t) =>
if (t |> getShape |> XYShape.T.length > 0) { if (t |> getShape |> XYShape.T.length > 0) {
switch (cache) { switch (cache) {
| Some(cache) => cache | Some(cache) => {
cache;
}
| None => | None =>
t t
|> getShape |> getShape
@ -254,7 +257,7 @@ module Continuous = {
|> updateKnownIntegralSum(Some(1.0)); |> updateKnownIntegralSum(Some(1.0));
}; };
let normalizedToContinuous = t => Some(t); // TODO: this should be normalized let normalizedToContinuous = t => Some(t |> normalize);
let normalizedToDiscrete = _ => None; let normalizedToDiscrete = _ => None;
let mean = (t: t) => { let mean = (t: t) => {
@ -1059,18 +1062,17 @@ module Shape = {
Continuous.T.normalizedToContinuous, Continuous.T.normalizedToContinuous,
)); ));
let minX = mapToAll((Mixed.T.minX, Discrete.T.minX, Continuous.T.minX)); let minX = mapToAll((Mixed.T.minX, Discrete.T.minX, Continuous.T.minX));
let integral = (~cache) => { let integral = (~cache) =>
mapToAll(( mapToAll((
Mixed.T.Integral.get(~cache), Mixed.T.Integral.get(~cache=None),
Discrete.T.Integral.get(~cache), Discrete.T.Integral.get(~cache=None),
Continuous.T.Integral.get(~cache), Continuous.T.Integral.get(~cache=None),
)); ));
};
let integralEndY = (~cache) => let integralEndY = (~cache) =>
mapToAll(( mapToAll((
Mixed.T.Integral.sum(~cache), Mixed.T.Integral.sum(~cache=None),
Discrete.T.Integral.sum(~cache), Discrete.T.Integral.sum(~cache),
Continuous.T.Integral.sum(~cache), Continuous.T.Integral.sum(~cache=None),
)); ));
let integralXtoY = (~cache, f) => { let integralXtoY = (~cache, f) => {
mapToAll(( mapToAll((
@ -1178,7 +1180,6 @@ module DistPlus = {
let normalize = (t: t): t => { let normalize = (t: t): t => {
let normalizedShape = t |> toShape |> Shape.T.normalize; let normalizedShape = t |> toShape |> Shape.T.normalize;
t |> updateShape(normalizedShape); t |> updateShape(normalizedShape);
// TODO: also adjust for domainIncludedProbabilityMass here. // TODO: also adjust for domainIncludedProbabilityMass here.
}; };
@ -1190,7 +1191,6 @@ module DistPlus = {
t |> updateShape(truncatedShape); t |> updateShape(truncatedShape);
}; };
// TODO: replace this with
let normalizedToContinuous = (t: t) => { let normalizedToContinuous = (t: t) => {
t t
|> toShape |> toShape
@ -1236,8 +1236,10 @@ module DistPlus = {
: t => : t =>
Shape.T.mapY(~knownIntegralSumFn, fn, shape) |> updateShape(_, t); Shape.T.mapY(~knownIntegralSumFn, fn, shape) |> updateShape(_, t);
let integralEndY = (~cache as _, t: t) => // get the total of everything
let integralEndY = (~cache as _, t: t) => {
Shape.T.Integral.sum(~cache=Some(t.integralCache), toShape(t)); Shape.T.Integral.sum(~cache=Some(t.integralCache), toShape(t));
}
// TODO: Fix this below, obviously. Adjust for limits // TODO: Fix this below, obviously. Adjust for limits
let integralXtoY = (~cache as _, f, t: t) => { let integralXtoY = (~cache as _, f, t: t) => {
@ -1247,8 +1249,9 @@ module DistPlus = {
// 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.
let integralYtoX = (~cache as _, f, t: t) => { let integralYtoX = (~cache as _, f, t: t) => {
Shape.T.Integral.yToX(~cache=Some(t.integralCache), f, toShape(t)); Shape.T.Integral.yToX(~cache=None, f, toShape(t));
}; };
let mean = (t: t) => { let mean = (t: t) => {
Shape.T.mean(t.shape); Shape.T.mean(t.shape);
}; };

View File

@ -168,8 +168,11 @@ module Normalize = {
let rec operationToLeaf = let rec operationToLeaf =
(toLeaf, renderParams, t: node): result(node, string) => { (toLeaf, renderParams, t: node): result(node, string) => {
switch (t) { switch (t) {
| `RenderedDist(s) => | `RenderedDist(s) => {
Ok(`RenderedDist(Distributions.Shape.T.normalize(s))) Js.log2("normed", Distributions.Shape.T.normalize(s));
//Js.log2("normed integral", Distributions.Shape.T.normalize(s)));
Ok(`RenderedDist(Distributions.Shape.T.normalize(s)));
}
| `SymbolicDist(_) => Ok(t) | `SymbolicDist(_) => Ok(t)
| _ => | _ =>
t t

View File

@ -258,11 +258,11 @@ module T = {
(~xSelection: [ | `Linear | `ByWeight]=`Linear, dist: symbolicDist, n) => { (~xSelection: [ | `Linear | `ByWeight]=`Linear, dist: symbolicDist, n) => {
switch (xSelection, dist) { switch (xSelection, dist) {
| (`Linear, _) => E.A.Floats.range(min(dist), max(dist), n) | (`Linear, _) => E.A.Floats.range(min(dist), max(dist), n)
/* | (`ByWeight, `Uniform(n)) => | (`ByWeight, `Uniform(n)) =>
// In `ByWeight mode, uniform distributions get special treatment because we need two x's // In `ByWeight mode, uniform distributions get special treatment because we need two x's
// on either side for proper rendering (just left and right of the discontinuities). // on either side for proper rendering (just left and right of the discontinuities).
let dx = 0.00001 *. (n.high -. n.low); let dx = 0.00001 *. (n.high -. n.low);
[|n.low -. dx, n.low +. dx, n.high -. dx, n.high +. dx|]; */ [|n.low -. dx, n.low +. dx, n.high -. dx, n.high +. dx|];
| (`ByWeight, _) => | (`ByWeight, _) =>
let ys = E.A.Floats.range(minCdfValue, maxCdfValue, n); let ys = E.A.Floats.range(minCdfValue, maxCdfValue, n);
ys |> E.A.fmap(y => inv(y, dist)); ys |> E.A.fmap(y => inv(y, dist));