diff --git a/src/components/CodeEditor.js b/src/components/CodeEditor.js index 5d0a8ba5..1bf00326 100644 --- a/src/components/CodeEditor.js +++ b/src/components/CodeEditor.js @@ -31,7 +31,7 @@ export class CodeEditor extends React.Component { }} setOptions={{ enableBasicAutocompletion: false, - enableLiveAutocompletion: false, + enableLiveAutocompletion: true, enableSnippets: true, }} /> diff --git a/src/distPlus/expressionTree/ExpressionTreeEvaluator.re b/src/distPlus/expressionTree/ExpressionTreeEvaluator.re index eade4b4b..996d9863 100644 --- a/src/distPlus/expressionTree/ExpressionTreeEvaluator.re +++ b/src/distPlus/expressionTree/ExpressionTreeEvaluator.re @@ -95,26 +95,28 @@ module VerticalScaling = { let operationToLeaf = (evaluationParams: evaluationParams, scaleOp, t, scaleBy) => { // scaleBy has to be a single float, otherwise we'll return an error. - let fn = (secondary,main) => Operation.Scale.toFn(scaleOp)(main, secondary); + let fn = (secondary, main) => + Operation.Scale.toFn(scaleOp, main, secondary); let integralSumCacheFn = Operation.Scale.toIntegralSumCacheFn(scaleOp); let integralCacheFn = Operation.Scale.toIntegralCacheFn(scaleOp); let renderedShape = Render.render(evaluationParams, t); - let s = switch (renderedShape, scaleBy) { - | (Ok(`RenderedDist(rs)), `SymbolicDist(`Float(scaleBy))) => - Ok( - `RenderedDist( - Shape.T.mapY( - ~integralSumCacheFn=integralSumCacheFn(scaleBy), - ~integralCacheFn=integralCacheFn(scaleBy), - ~fn=fn(scaleBy), - rs, + let s = + switch (renderedShape, scaleBy) { + | (Ok(`RenderedDist(rs)), `SymbolicDist(`Float(scaleBy))) => + Ok( + `RenderedDist( + Shape.T.mapY( + ~integralSumCacheFn=integralSumCacheFn(scaleBy), + ~integralCacheFn=integralCacheFn(scaleBy), + ~fn=fn(scaleBy), + rs, + ), ), - ), - ) - | (Error(e1), _) => Error(e1) - | (_, _) => Error("Can only scale by float values.") - }; + ) + | (Error(e1), _) => Error(e1) + | (_, _) => Error("Can only scale by float values.") + }; s; }; }; @@ -265,9 +267,7 @@ module FloatFromDist = { // TODO: This forces things to be floats let callableFunction = (evaluationParams, name, args) => { args - |> E.A.fmap(a => - Render.render(evaluationParams, a) |> E.R.bind(_, Render.toFloat) - ) + |> E.A.fmap(a => evaluationParams.evaluateNode(evaluationParams, a)) |> E.A.R.firstErrorOrOpen |> E.R.bind(_, Functions.fnn(evaluationParams, name)); }; @@ -299,11 +299,11 @@ module Render = { This function is used mainly to turn a parse tree into a single RenderedDist that can then be displayed to the user. */ let rec toLeaf = - ( - evaluationParams: ExpressionTypes.ExpressionTree.evaluationParams, - node: t, - ) - : result(t, string) => { + ( + evaluationParams: ExpressionTypes.ExpressionTree.evaluationParams, + node: t, + ) + : result(t, string) => { switch (node) { // Leaf nodes just stay leaf nodes | `SymbolicDist(_) diff --git a/src/distPlus/expressionTree/ExpressionTypes.re b/src/distPlus/expressionTree/ExpressionTypes.re index 55ef37ce..ec359a4c 100644 --- a/src/distPlus/expressionTree/ExpressionTypes.re +++ b/src/distPlus/expressionTree/ExpressionTypes.re @@ -31,6 +31,10 @@ module ExpressionTree = { | `FunctionCall(string, array(node)) ]; // Have nil as option + let getFloat = (node:node) => node |> fun + | `RenderedDist(Discrete({xyShape: {xs: [|x|], ys: [|1.0|]}})) => Some(x) + | `SymbolicDist(`Float(x)) => Some(x) + | _ => None type samplingInputs = { sampleCount: int, @@ -87,6 +91,7 @@ module ExpressionTree = { |> evaluationParams.evaluateNode(evaluationParams) |> E.R.bind(_, fn(evaluationParams)); + module Render = { type t = node; diff --git a/src/distPlus/expressionTree/Functions.re b/src/distPlus/expressionTree/Functions.re index dd14a218..cddc698b 100644 --- a/src/distPlus/expressionTree/Functions.re +++ b/src/distPlus/expressionTree/Functions.re @@ -1,21 +1,17 @@ type node = ExpressionTypes.ExpressionTree.node; let toOkSym = r => Ok(`SymbolicDist(r)); +let getFloat = ExpressionTypes.ExpressionTree.getFloat; let twoFloats = (fn, n1: node, n2: node): result(node, string) => - switch (n1, n2) { - | (`SymbolicDist(`Float(a)), `SymbolicDist(`Float(b))) => fn(a, b) - | _ => Error("Variables have wrong type") + switch (getFloat(n1), getFloat(n2)) { + | (Some(a), Some(b)) => fn(a, b) + | _ => Error("Function needed two floats, missing them.") }; let threeFloats = (fn, n1: node, n2: node, n3: node): result(node, string) => - switch (n1, n2, n3) { - | ( - `SymbolicDist(`Float(a)), - `SymbolicDist(`Float(b)), - `SymbolicDist(`Float(c)), - ) => - fn(a, b, c) + switch (getFloat(n1), getFloat(n2), getFloat(n3)) { + | (Some(a), Some(b), Some(c)) => fn(a, b, c) | _ => Error("Variables have wrong type") }; @@ -35,18 +31,15 @@ let apply3 = (fn, args: array(node)): result(node, string) => | _ => Error("Needs 3 args") }; -let to_: (float, float) => result(node, string) = (low, high) => switch(low,high){ - | (low,high) - when low <= 0.0 && low < high => { - Ok(`SymbolicDist(SymbolicDist.Normal.from90PercentCI(low, high))); - } - | (low,high) - when low < high => { - Ok(`SymbolicDist(SymbolicDist.Lognormal.from90PercentCI(low, high))); - } - | (low,high) => - Error("Low value must be less than high value.") -} +let to_: (float, float) => result(node, string) = + (low, high) => + switch (low, high) { + | (low, high) when low <= 0.0 && low < high => + Ok(`SymbolicDist(SymbolicDist.Normal.from90PercentCI(low, high))) + | (low, high) when low < high => + Ok(`SymbolicDist(SymbolicDist.Lognormal.from90PercentCI(low, high))) + | (low, high) => Error("Low value must be less than high value.") + }; // Possible setup: // let normal = {"inputs": [`float, `float], "outputs": [`float]}; @@ -86,16 +79,57 @@ let fnn = | _ => Error("Needs 3 valid arguments") } | ("triangular", _) => - switch (args) { - | [| - `SymbolicDist(`Float(a)), - `SymbolicDist(`Float(b)), - `SymbolicDist(`Float(c)), - |] => + switch (args |> E.A.fmap(getFloat)) { + | [|Some(a), Some(b), Some(c)|] => SymbolicDist.Triangular.make(a, b, c) |> E.R.fmap(r => `SymbolicDist(r)) | _ => Error("Needs 3 valid arguments") } | ("to", _) => apply2(twoFloats(to_), args) + | ("pdf", _) => switch(args){ + | [|fst,snd|] => { + switch(PTypes.SamplingDistribution.renderIfIsNotSamplingDistribution(evaluationParams,fst),getFloat(snd)){ + | (Ok(fst), Some(flt)) => Ok(`FloatFromDist(`Pdf(flt), fst)) + | _ => Error("Incorrect arguments") + } + } + | _ => Error("Needs two args") + } + | ("inv", _) => switch(args){ + | [|fst,snd|] => { + switch(PTypes.SamplingDistribution.renderIfIsNotSamplingDistribution(evaluationParams,fst),getFloat(snd)){ + | (Ok(fst), Some(flt)) => Ok(`FloatFromDist(`Inv(flt), fst)) + | _ => Error("Incorrect arguments") + } + } + | _ => Error("Needs two args") + } + | ("cdf", _) => switch(args){ + | [|fst,snd|] => { + switch(PTypes.SamplingDistribution.renderIfIsNotSamplingDistribution(evaluationParams,fst),getFloat(snd)){ + | (Ok(fst), Some(flt)) => Ok(`FloatFromDist(`Cdf(flt), fst)) + | _ => Error("Incorrect arguments") + } + } + | _ => Error("Needs two args") + } + | ("mean", _) => switch(args){ + | [|fst|] => { + switch(PTypes.SamplingDistribution.renderIfIsNotSamplingDistribution(evaluationParams,fst)){ + | (Ok(fst)) => Ok(`FloatFromDist(`Mean,fst)) + | _ => Error("Incorrect arguments") + } + } + | _ => Error("Needs two args") + } + | ("sample", _) => switch(args){ + | [|fst|] => { + switch(PTypes.SamplingDistribution.renderIfIsNotSamplingDistribution(evaluationParams,fst)){ + | (Ok(fst)) => Ok(`FloatFromDist(`Sample,fst)) + | _ => Error("Incorrect arguments") + } + } + | _ => Error("Needs two args") + } | _ => Error("Function " ++ name ++ " not found") }; diff --git a/src/distPlus/expressionTree/MathJsParser.re b/src/distPlus/expressionTree/MathJsParser.re index 0602695a..2ae5fef2 100644 --- a/src/distPlus/expressionTree/MathJsParser.re +++ b/src/distPlus/expressionTree/MathJsParser.re @@ -236,14 +236,6 @@ module MathAdtToDistDst = { ) | ("scaleLog", [|d, `SymbolicDist(`Float(v))|]) => Ok(`VerticalScaling((`Log, d, `SymbolicDist(`Float(v))))) - | ("pdf", [|d, `SymbolicDist(`Float(v))|]) => - toOkFloatFromDist((`Pdf(v), d)) - | ("cdf", [|d, `SymbolicDist(`Float(v))|]) => - toOkFloatFromDist((`Cdf(v), d)) - | ("inv", [|d, `SymbolicDist(`Float(v))|]) => - toOkFloatFromDist((`Inv(v), d)) - | ("mean", [|d|]) => toOkFloatFromDist((`Mean, d)) - | ("sample", [|d|]) => toOkFloatFromDist((`Sample, d)) | _ => Error("This type not currently supported") } }); @@ -294,12 +286,7 @@ module MathAdtToDistDst = { | "scaleMultiply" | "scaleExp" | "scaleLog" - | "truncate" - | "mean" - | "inv" - | "sample" - | "cdf" - | "pdf" => operationParser(name, parseArgs()) + | "truncate" => operationParser(name, parseArgs()) | name => parseArgs() |> E.R.fmap((args: array(ExpressionTypes.ExpressionTree.node)) =>