Fixed minor bugs

This commit is contained in:
Ozzie Gooen 2020-08-11 10:59:02 +01:00
parent 31e4f97820
commit c39d749a1d
6 changed files with 136 additions and 54 deletions

View File

@ -4,6 +4,7 @@ import AceEditor from "react-ace";
import "ace-builds/src-noconflict/mode-golang"; import "ace-builds/src-noconflict/mode-golang";
import "ace-builds/src-noconflict/theme-github"; import "ace-builds/src-noconflict/theme-github";
import "ace-builds/src-noconflict/ext-language_tools"; import "ace-builds/src-noconflict/ext-language_tools";
import "ace-builds/src-noconflict/keybinding-vim";
function onChange(newValue) { function onChange(newValue) {
console.log("change", newValue); console.log("change", newValue);
@ -20,6 +21,7 @@ export class CodeEditor extends React.Component {
mode="golang" mode="golang"
height="400px" height="400px"
width="100%" width="100%"
keyboardHandler="vim"
theme="github" theme="github"
showGutter={false} showGutter={false}
highlightActiveLine={false} highlightActiveLine={false}

View File

@ -163,6 +163,8 @@ module DemoDist = {
switch (response1) { switch (response1) {
| Ok(`DistPlus(distPlus1)) => | Ok(`DistPlus(distPlus1)) =>
<DistPlusPlot distPlus={DistPlus.T.normalize(distPlus1)} /> <DistPlusPlot distPlus={DistPlus.T.normalize(distPlus1)} />
| Ok(`Float(f)) =>
<ForetoldComponents.NumberShower number=f precision=3 />
| Ok(`Function((f, a), env)) => | Ok(`Function((f, a), env)) =>
// Problem: When it gets the function, it doesn't save state about previous commands // Problem: When it gets the function, it doesn't save state about previous commands
let foo: DistPlusRenderer.Inputs.inputs = { let foo: DistPlusRenderer.Inputs.inputs = {
@ -181,7 +183,7 @@ module DemoDist = {
|> E.R.bind(_, a => |> E.R.bind(_, a =>
switch (a) { switch (a) {
| `DistPlus(d) => Ok((r, DistPlus.T.normalize(d))) | `DistPlus(d) => Ok((r, DistPlus.T.normalize(d)))
| _ => Error("") | n => {Js.log2("Error here",n); Error("wrong type")}
} }
) )
) )

View File

@ -3,13 +3,21 @@ open Distributions;
type t = DistTypes.continuousShape; type t = DistTypes.continuousShape;
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 => {
xyShape, xyShape,
interpolation, interpolation,
integralSumCache, integralSumCache,
integralCache, integralCache,
}; };
let shapeMap = (fn, {xyShape, interpolation, integralSumCache, integralCache}: t): t => { let shapeMap =
(fn, {xyShape, interpolation, integralSumCache, integralCache}: t): t => {
xyShape: fn(xyShape), xyShape: fn(xyShape),
interpolation, interpolation,
integralSumCache, integralSumCache,
@ -19,10 +27,14 @@ let lastY = (t: t) => t |> getShape |> XYShape.T.lastY;
let oShapeMap = let oShapeMap =
(fn, {xyShape, interpolation, integralSumCache, integralCache}: t) (fn, {xyShape, interpolation, integralSumCache, integralCache}: t)
: option(DistTypes.continuousShape) => : option(DistTypes.continuousShape) =>
fn(xyShape) |> E.O.fmap(make(~interpolation, ~integralSumCache, ~integralCache)); fn(xyShape)
|> E.O.fmap(make(~interpolation, ~integralSumCache, ~integralCache));
let emptyIntegral: DistTypes.continuousShape = { let emptyIntegral: DistTypes.continuousShape = {
xyShape: {xs: [|neg_infinity|], ys: [|0.0|]}, xyShape: {
xs: [|neg_infinity|],
ys: [|0.0|],
},
interpolation: `Linear, interpolation: `Linear,
integralSumCache: Some(0.0), integralSumCache: Some(0.0),
integralCache: None, integralCache: None,
@ -35,14 +47,18 @@ let empty: DistTypes.continuousShape = {
}; };
let stepwiseToLinear = (t: t): t => let stepwiseToLinear = (t: t): t =>
make(~integralSumCache=t.integralSumCache, ~integralCache=t.integralCache, XYShape.Range.stepwiseToLinear(t.xyShape)); make(
~integralSumCache=t.integralSumCache,
~integralCache=t.integralCache,
XYShape.Range.stepwiseToLinear(t.xyShape),
);
// Note: This results in a distribution with as many points as the sum of those in t1 and t2. // Note: This results in a distribution with as many points as the sum of those in t1 and t2.
let combinePointwise = let combinePointwise =
( (
~integralSumCachesFn=(_, _) => None, ~integralSumCachesFn=(_, _) => None,
~integralCachesFn: (t, t) => option(t) =(_, _) => None, ~integralCachesFn: (t, t) => option(t)=(_, _) => None,
~distributionType: DistTypes.distributionType = `PDF, ~distributionType: DistTypes.distributionType=`PDF,
fn: (float, float) => float, fn: (float, float) => float,
t1: DistTypes.continuousShape, t1: DistTypes.continuousShape,
t2: DistTypes.continuousShape, t2: DistTypes.continuousShape,
@ -62,19 +78,22 @@ let combinePointwise =
// If combining stepwise and linear, we must convert the stepwise to linear first, // If combining stepwise and linear, we must convert the stepwise to linear first,
// i.e. add a point at the bottom of each step // i.e. add a point at the bottom of each step
let (t1, t2) = switch (t1.interpolation, t2.interpolation) { let (t1, t2) =
| (`Linear, `Linear) => (t1, t2); switch (t1.interpolation, t2.interpolation) {
| (`Stepwise, `Stepwise) => (t1, t2); | (`Linear, `Linear) => (t1, t2)
| (`Linear, `Stepwise) => (t1, stepwiseToLinear(t2)); | (`Stepwise, `Stepwise) => (t1, t2)
| (`Stepwise, `Linear) => (stepwiseToLinear(t1), t2); | (`Linear, `Stepwise) => (t1, stepwiseToLinear(t2))
| (`Stepwise, `Linear) => (stepwiseToLinear(t1), t2)
}; };
let extrapolation = switch (distributionType) { let extrapolation =
switch (distributionType) {
| `PDF => `UseZero | `PDF => `UseZero
| `CDF => `UseOutermostPoints | `CDF => `UseOutermostPoints
}; };
let interpolator = XYShape.XtoY.continuousInterpolator(t1.interpolation, extrapolation); let interpolator =
XYShape.XtoY.continuousInterpolator(t1.interpolation, extrapolation);
make( make(
~integralSumCache=combinedIntegralSum, ~integralSumCache=combinedIntegralSum,
@ -103,10 +122,7 @@ let updateIntegralSumCache = (integralSumCache, t: t): t => {
integralSumCache, integralSumCache,
}; };
let updateIntegralCache = (integralCache, t: t): t => { let updateIntegralCache = (integralCache, t: t): t => {...t, integralCache};
...t,
integralCache,
};
let reduce = let reduce =
( (
@ -116,11 +132,13 @@ let reduce =
continuousShapes, continuousShapes,
) => ) =>
continuousShapes continuousShapes
|> E.A.fold_left(combinePointwise(~integralSumCachesFn, ~integralCachesFn, fn), empty); |> E.A.fold_left(
combinePointwise(~integralSumCachesFn, ~integralCachesFn, fn),
empty,
);
let mapY = (~integralSumCacheFn=_ => None, let mapY =
~integralCacheFn=_ => None, (~integralSumCacheFn=_ => None, ~integralCacheFn=_ => None, ~fn, t: t) => {
~fn, t: t) => {
make( make(
~interpolation=t.interpolation, ~interpolation=t.interpolation,
~integralSumCache=t.integralSumCache |> E.O.bind(_, integralSumCacheFn), ~integralSumCache=t.integralSumCache |> E.O.bind(_, integralSumCacheFn),
@ -130,13 +148,15 @@ let mapY = (~integralSumCacheFn=_ => None,
}; };
let rec scaleBy = (~scale=1.0, t: t): t => { let rec scaleBy = (~scale=1.0, t: t): t => {
let scaledIntegralSumCache = E.O.bind(t.integralSumCache, v => Some(scale *. v)); let scaledIntegralSumCache =
let scaledIntegralCache = E.O.bind(t.integralCache, v => Some(scaleBy(~scale, v))); E.O.bind(t.integralSumCache, v => Some(scale *. v));
let scaledIntegralCache =
E.O.bind(t.integralCache, v => Some(scaleBy(~scale, v)));
t t
|> mapY(~fn=(r: float) => r *. scale) |> mapY(~fn=(r: float) => r *. scale)
|> updateIntegralSumCache(scaledIntegralSumCache) |> updateIntegralSumCache(scaledIntegralSumCache)
|> updateIntegralCache(scaledIntegralCache) |> updateIntegralCache(scaledIntegralCache);
}; };
module T = module T =
@ -171,20 +191,22 @@ module T =
|> XYShape.Zipped.filterByX(x => x >= lc && x <= rc); |> XYShape.Zipped.filterByX(x => x >= lc && x <= rc);
let leftNewPoint = let leftNewPoint =
leftCutoff |> E.O.dimap(lc => [|(lc -. epsilon_float, 0.)|], _ => [||]); leftCutoff
|> E.O.dimap(lc => [|(lc -. epsilon_float, 0.)|], _ => [||]);
let rightNewPoint = let rightNewPoint =
rightCutoff |> E.O.dimap(rc => [|(rc +. epsilon_float, 0.)|], _ => [||]); rightCutoff
|> E.O.dimap(rc => [|(rc +. epsilon_float, 0.)|], _ => [||]);
let truncatedZippedPairsWithNewPoints = let truncatedZippedPairsWithNewPoints =
E.A.concatMany([|leftNewPoint, truncatedZippedPairs, rightNewPoint|]); E.A.concatMany([|leftNewPoint, truncatedZippedPairs, rightNewPoint|]);
let truncatedShape = let truncatedShape =
XYShape.T.fromZippedArray(truncatedZippedPairsWithNewPoints); XYShape.T.fromZippedArray(truncatedZippedPairsWithNewPoints);
make(truncatedShape) make(truncatedShape);
}; };
// TODO: This should work with stepwise plots. // TODO: This should work with stepwise plots.
let integral = (t) => let integral = t =>
switch (getShape(t) |> XYShape.T.isEmpty, t.integralCache) { switch (getShape(t) |> XYShape.T.isEmpty, t.integralCache) {
| (true, _) => emptyIntegral | (true, _) => emptyIntegral
| (false, Some(cache)) => cache | (false, Some(cache)) => cache
@ -253,22 +275,37 @@ let combineAlgebraicallyWithDiscrete =
if (XYShape.T.isEmpty(t1s) || XYShape.T.isEmpty(t2s)) { if (XYShape.T.isEmpty(t1s) || XYShape.T.isEmpty(t2s)) {
empty; empty;
} else { } else {
let continuousAsLinear = switch (t1.interpolation) { let continuousAsLinear =
| `Linear => t1; switch (t1.interpolation) {
| `Linear => t1
| `Stepwise => stepwiseToLinear(t1) | `Stepwise => stepwiseToLinear(t1)
}; };
let combinedShape = AlgebraicShapeCombination.combineShapesContinuousDiscrete(op, continuousAsLinear |> getShape, t2s); let combinedShape =
AlgebraicShapeCombination.combineShapesContinuousDiscrete(
op,
continuousAsLinear |> getShape,
t2s,
);
let combinedIntegralSum = let combinedIntegralSum =
switch (op) {
| `Multiply
| `Divide =>
Common.combineIntegralSums( Common.combineIntegralSums(
(a, b) => Some(a *. b), (a, b) => Some(a *. b),
t1.integralSumCache, t1.integralSumCache,
t2.integralSumCache, t2.integralSumCache,
); )
| _ => None
};
// TODO: It could make sense to automatically transform the integrals here (shift or scale) // TODO: It could make sense to automatically transform the integrals here (shift or scale)
make(~interpolation=t1.interpolation, ~integralSumCache=combinedIntegralSum, combinedShape) make(
~interpolation=t1.interpolation,
~integralSumCache=combinedIntegralSum,
combinedShape,
);
}; };
}; };

View File

@ -346,6 +346,7 @@ let rec toLeaf =
|> E.R.bind(_, toLeaf(evaluationParams)) |> E.R.bind(_, toLeaf(evaluationParams))
| `FunctionCall(name, args) => | `FunctionCall(name, args) =>
callableFunction(evaluationParams, name, args) callableFunction(evaluationParams, name, args)
|> E.R.bind(_, toLeaf(evaluationParams))
| `MultiModal(r) => | `MultiModal(r) =>
let components = let components =
r r
@ -363,6 +364,7 @@ let rec toLeaf =
(acc, x) => {`PointwiseCombination((`Add, acc, x))}, (acc, x) => {`PointwiseCombination((`Add, acc, x))},
E.A.unsafe_get(components, 0), E.A.unsafe_get(components, 0),
); );
Ok(`Render(`Normalize(pointwiseSum))); Ok(`Normalize(pointwiseSum))
|> E.R.bind(_, toLeaf(evaluationParams))
}; };
}; };

View File

@ -38,6 +38,11 @@ module ExpressionTree = {
| `SymbolicDist(`Float(x)) => Some(x) | `SymbolicDist(`Float(x)) => Some(x)
| _ => None | _ => None
let toFloatIfNeeded = (node:node) => switch(node |> getFloat){
| Some(float) => `SymbolicDist(`Float(float))
| None => node
}
type samplingInputs = { type samplingInputs = {
sampleCount: int, sampleCount: int,
outputXYPoints: int, outputXYPoints: int,

View File

@ -112,7 +112,10 @@ module Internals = {
ins := addVariable(ins^, name, node); ins := addVariable(ins^, name, node);
None; None;
} }
| `Expression(node) => Some(runNode(ins^, node) |> E.R.fmap(r => (ins^.environment, r))), | `Expression(node) =>
Some(
runNode(ins^, node) |> E.R.fmap(r => (ins^.environment, r)),
),
) )
|> E.A.O.concatSomes |> E.A.O.concatSomes
|> E.A.R.firstErrorOrOpen; |> E.A.R.firstErrorOrOpen;
@ -142,12 +145,13 @@ let renderIfNeeded =
|> ( |> (
fun fun
| `MultiModal(_) as n | `MultiModal(_) as n
| `Normalize(_) as n
| `SymbolicDist(_) as n => { | `SymbolicDist(_) as n => {
`Render(n) `Render(n)
|> Internals.runNode(Internals.distPlusRenderInputsToInputs(inputs)) |> Internals.runNode(Internals.distPlusRenderInputsToInputs(inputs))
|> ( |> (
fun fun
| Ok(`RenderedDist(n)) => Ok(`RenderedDist(n)) | Ok(`RenderedDist(_)) as r => r
| Error(r) => Error(r) | Error(r) => Error(r)
| _ => Error("Didn't render, but intended to") | _ => Error("Didn't render, but intended to")
); );
@ -159,7 +163,7 @@ let run = (inputs: Inputs.inputs) => {
inputs inputs
|> Internals.distPlusRenderInputsToInputs |> Internals.distPlusRenderInputsToInputs
|> Internals.inputsToLeaf |> Internals.inputsToLeaf
|> E.R.bind(_, ((lastIns,r)) => |> E.R.bind(_, ((lastIns, r)) =>
r r
|> renderIfNeeded(inputs) |> renderIfNeeded(inputs)
|> ( |> (
@ -176,7 +180,37 @@ let run = (inputs: Inputs.inputs) => {
|> E.R.fmap(Internals.outputToDistPlus(inputs)); |> E.R.fmap(Internals.outputToDistPlus(inputs));
}; };
let exportDistPlus = (inputs, env:ProbExample.ExpressionTypes.ExpressionTree.environment, node: ExpressionTypes.ExpressionTree.node) => let exportDistPlus =
(
inputs,
env: ProbExample.ExpressionTypes.ExpressionTree.environment,
node: ExpressionTypes.ExpressionTree.node,
) =>
node
|> renderIfNeeded(inputs)
|> E.R.bind(
_,
fun
| `RenderedDist(Discrete({xyShape: {xs: [|x|], ys: [|1.0|]}})) =>
Ok(`Float(x))
| `SymbolicDist(`Float(x)) => Ok(`Float(x))
| `RenderedDist(n) =>
Ok(`DistPlus(Internals.outputToDistPlus(inputs, n)))
| `Function(n) => Ok(`Function((n, env)))
| n =>
Error(
"Didn't output a rendered distribution. Format:"
++ ExpressionTree.toString(n),
),
);
// This isn't ok with floats, which can't be done in a function easily
let exportDistPlus2 =
(
inputs,
env: ProbExample.ExpressionTypes.ExpressionTree.environment,
node: ExpressionTypes.ExpressionTree.node,
) =>
node node
|> renderIfNeeded(inputs) |> renderIfNeeded(inputs)
|> E.R.bind( |> E.R.bind(
@ -184,7 +218,7 @@ let exportDistPlus = (inputs, env:ProbExample.ExpressionTypes.ExpressionTree.env
fun fun
| `RenderedDist(n) => | `RenderedDist(n) =>
Ok(`DistPlus(Internals.outputToDistPlus(inputs, n))) Ok(`DistPlus(Internals.outputToDistPlus(inputs, n)))
| `Function(n) => Ok(`Function(n, env)) | `Function(n) => Ok(`Function((n, env)))
| n => | n =>
Error( Error(
"Didn't output a rendered distribution. Format:" "Didn't output a rendered distribution. Format:"
@ -196,7 +230,7 @@ let run2 = (inputs: Inputs.inputs) => {
inputs inputs
|> Internals.distPlusRenderInputsToInputs |> Internals.distPlusRenderInputsToInputs
|> Internals.inputsToLeaf |> Internals.inputsToLeaf
|> E.R.bind(_,((a,b)) => exportDistPlus(inputs,a,b)) |> E.R.bind(_, ((a, b)) => exportDistPlus(inputs, a, b));
}; };
let runFunction = let runFunction =
@ -213,5 +247,5 @@ let runFunction =
fnInputs, fnInputs,
fn, fn,
); );
output |> E.R.bind(_, exportDistPlus(ins, inputs.environment)); output |> E.R.bind(_, exportDistPlus2(ins, inputs.environment));
}; };