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);
Js.log(response);
switch (RenderTypes.DistPlusRenderer.Outputs.distplus(response)) {
| Some(distPlus) => <DistPlusPlot distPlus />
| _ =>
@ -172,7 +171,7 @@ let make = () => {
~onSubmit=({state}) => {None},
~initialState={
//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",
xPoint: "50.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
let combineVariancesFn =
switch (op) {
| `Add => ((v1, v2, m1, m2) => v1 +. v2)
| `Subtract => ((v1, v2, m1, m2) => v1 +. v2)
| `Add => ((v1, v2, _, _) => v1 +. v2)
| `Subtract => ((v1, v2, _, _) => v1 +. v2)
| `Multiply => (
(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(variances, k, variance);
// update bounds
let minX = mean -. variance *. 1.644854;
let maxX = mean +. variance *. 1.644854;
let minX = mean -. 2. *. sqrt(variance) *. 1.644854;
let maxX = mean +. 2. *. sqrt(variance) *. 1.644854;
if (minX < outputMinX^) {
outputMinX := minX;
};
@ -193,11 +193,11 @@ let combineShapesContinuousContinuous =
let outputXs: array(float) = E.A.Floats.range(outputMinX^, outputMaxX^, nOut);
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.
for (j in 0 to E.A.length(masses) - 1) {
let _ = if (variances[j] > 0.) {
for (i in 0 to E.A.length(outputXs) - 1) {
for (j in 0 to E.A.length(masses) - 1) { // go through all of the result points
let _ = if (variances[j] > 0. && masses[j] > 0.) {
for (i in 0 to E.A.length(outputXs) - 1) { // go through all of the target points
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);
();
};

View File

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

View File

@ -168,8 +168,11 @@ module Normalize = {
let rec operationToLeaf =
(toLeaf, renderParams, t: node): result(node, string) => {
switch (t) {
| `RenderedDist(s) =>
Ok(`RenderedDist(Distributions.Shape.T.normalize(s)))
| `RenderedDist(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)
| _ =>
t

View File

@ -258,11 +258,11 @@ module T = {
(~xSelection: [ | `Linear | `ByWeight]=`Linear, dist: symbolicDist, n) => {
switch (xSelection, dist) {
| (`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
// on either side for proper rendering (just left and right of the discontinuities).
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, _) =>
let ys = E.A.Floats.range(minCdfValue, maxCdfValue, n);
ys |> E.A.fmap(y => inv(y, dist));