First attempt at simple working environment

This commit is contained in:
Ozzie Gooen 2020-07-31 09:00:12 +01:00
parent 67828cf789
commit e1374ee69b
7 changed files with 117 additions and 57 deletions

View File

@ -152,7 +152,7 @@ module DemoDist = {
shapeLength: Some(options.downsampleTo |> E.O.default(1000))
},
~distPlusIngredients,
~inputVariables=
~environment=
[|("p", `SymbolicDist(`Float(1.0)))|]
->Belt.Map.String.fromArray,
(),

View File

@ -393,6 +393,7 @@ module Draw = {
let normalShape =
ExpressionTree.toShape(
{sampleCount: 10000, outputXYPoints: 10000, kernelWidth: None, shapeLength:numSamples},
ExpressionTypes.ExpressionTree.Environment.empty,
`SymbolicDist(normal),
) |> E.R.toExn;
let xyShape: Types.xyShape =

View File

@ -1,17 +1,17 @@
open ExpressionTypes.ExpressionTree;
let toLeaf = (samplingInputs, node: node) => {
let toLeaf = (samplingInputs, environment, node: node) => {
node
|> ExpressionTreeEvaluator.toLeaf({
samplingInputs,
environment,
evaluateNode: ExpressionTreeEvaluator.toLeaf,
});
};
let toShape = (samplingInputs, node: node) => {
let toShape = (samplingInputs, environment, node: node) => {
let renderResult =
`Render(`Normalize(node))
|> toLeaf(samplingInputs);
`Render(`Normalize(node)) |> toLeaf(samplingInputs, environment);
switch (renderResult) {
| Ok(`RenderedDist(shape)) => Ok(shape)

View File

@ -335,6 +335,7 @@ let toLeaf =
| `Normalize(t) => Normalize.operationToLeaf(evaluationParams, t)
| `Render(t) => Render.operationToLeaf(evaluationParams, t)
| `Function(t) => Ok(`Function(t))
| `Symbol(r) => ExpressionTypes.ExpressionTree.Environment.get(evaluationParams.environment, r) |> E.O.toResult("Undeclared variable " ++ r)
| `CallableFunction(name, args) =>
callableFunction(evaluationParams, name, args)
};

View File

@ -22,6 +22,7 @@ module ExpressionTree = {
| `FloatFromDist(distToFloatOperation, node)
| `Function(node => result(node, string))
| `CallableFunction(string, array(node))
| `Symbol(string)
];
type samplingInputs = {
@ -31,8 +32,18 @@ module ExpressionTree = {
shapeLength: int
};
type environment = Belt.Map.String.t(node);
module Environment = {
type t = environment
let empty:t = [||]->Belt.Map.String.fromArray
let update = (t,str, fn) => Belt.Map.String.update(t, str, fn)
let get = (t,str) => Belt.Map.String.get(t, str)
}
type evaluationParams = {
samplingInputs,
environment,
evaluateNode: (evaluationParams, node) => Belt.Result.t(node, string),
};

View File

@ -8,7 +8,7 @@ module MathJsonToMathJsAdt = {
| Array(array(arg))
| Blocks(array(arg))
| Object(Js.Dict.t(arg))
| Assignment(arg,arg)
| Assignment(arg, arg)
and fn = {
name: string,
args: array(arg),
@ -44,19 +44,17 @@ module MathJsonToMathJsAdt = {
let items = field("items", array(run), j);
Some(Array(items |> E.A.O.concatSomes));
| "SymbolNode" => Some(Symbol(field("name", string, j)))
| "AssignmentNode" => {
| "AssignmentNode" =>
let object_ = j |> field("object", run);
let value_ = j |> field("value", run);
switch(object_, value_){
| (Some(o), Some(v)) => Some(Assignment(o,v))
switch (object_, value_) {
| (Some(o), Some(v)) => Some(Assignment(o, v))
| _ => None
}
}
| "BlockNode" => {
};
| "BlockNode" =>
let block = r => r |> field("node", run);
let args = j |> field("blocks", array(block)) |> E.A.O.concatSomes;
Some(Blocks(args))
}
Some(Blocks(args));
| n =>
Js.log3("Couldn't parse mathjs node", j, n);
None;
@ -68,10 +66,7 @@ module MathAdtToDistDst = {
open MathJsonToMathJsAdt;
let handleSymbol = (inputVars: inputVars, sym) => {
switch (Belt.Map.String.get(inputVars, sym)) {
| Some(s) => Ok(s)
| None => Error("Couldn't find symbol " ++ sym)
};
Ok(`Symbol(sym))
};
module MathAdtCleaner = {
@ -100,7 +95,7 @@ module MathAdtToDistDst = {
| Symbol(s) => Symbol(s)
| Value(v) => Value(v)
| Blocks(args) => Blocks(args |> E.A.fmap(run))
| Assignment(a,b) => Assignment(a,run(b))
| Assignment(a, b) => Assignment(a, run(b))
| Object(v) =>
Object(
v
@ -122,7 +117,10 @@ module MathAdtToDistDst = {
)
| (_, _, Ok(mu), Ok(sigma)) =>
Ok(`CallableFunction(("lognormal", [|mu, sigma|])))
| _ => Error("Lognormal distribution needs either mean and stdev or mu and sigma")
| _ =>
Error(
"Lognormal distribution needs either mean and stdev or mu and sigma",
)
};
| _ =>
parseArgs()
@ -293,25 +291,40 @@ module MathAdtToDistDst = {
inputVars =>
fun
| Value(f) => Ok(`SymbolicDist(`Float(f)))
| Symbol(s) => handleSymbol(inputVars, s)
| Symbol(sym) => Ok(`Symbol(sym))
| Fn({name, args}) =>
functionParser(nodeParser(inputVars), name, args)
| _ => {
Error("This type not currently supported");
};
let rec topLevel = inputVars =>
fun
| Value(_) as r => nodeParser(inputVars, r)
| Fn(_) as r => nodeParser(inputVars, r)
let rec topLevel =
(inputVars: inputVars, r)
: result(ExpressionTypes.Program.program, string) =>
switch (r) {
| Value(_) as r =>
nodeParser(inputVars, r) |> E.R.fmap(r => [|`Expression(r)|])
| Fn(_) as r =>
nodeParser(inputVars, r) |> E.R.fmap(r => [|`Expression(r)|])
| Array(_) => Error("Array not valid as top level")
| Symbol(s) => handleSymbol(inputVars, s)
| Symbol(s) =>
handleSymbol(inputVars, s) |> E.R.fmap(r => [|`Expression(r)|])
| Object(_) => Error("Object not valid as top level")
| Assignment(_) => Error("Assignment not valid as top level")
| Blocks(blocks) => E.A.last(blocks) |> E.O.toResult("no blocks listed") |> E.R.bind(_, topLevel(inputVars))
| Assignment(name, value) =>
switch (name) {
| Symbol(symbol) =>
nodeParser(inputVars, value)
|> E.R.fmap(r => [|`Assignment((symbol, r))|])
| _ => Error("Symbol not a string")
}
| Blocks(blocks) =>
blocks
|> E.A.fmap(b => topLevel(inputVars, b))
|> E.A.R.firstErrorOrOpen
|> E.R.fmap(E.A.concatMany)
};
let run =
(inputVars, r): result(ExpressionTypes.ExpressionTree.node, string) =>
let run = (inputVars, r): result(ExpressionTypes.Program.program, string) =>
r |> MathAdtCleaner.run |> topLevel(inputVars);
};

View File

@ -31,29 +31,31 @@ module Inputs = {
unit,
};
};
type inputs = {
distPlusIngredients: ingredients,
samplingInputs: SamplingInputs.t,
inputVariables: Belt.Map.String.t(ExpressionTypes.ExpressionTree.node),
environment: ExpressionTypes.ExpressionTree.environment
};
let empty: SamplingInputs.t = {
sampleCount: None,
outputXYPoints: None,
kernelWidth: None,
shapeLength: None
shapeLength: None,
};
let make =
(
~samplingInputs=empty,
~distPlusIngredients,
~inputVariables=[||]->Belt.Map.String.fromArray,
~environment=ExpressionTypes.ExpressionTree.Environment.empty,
(),
)
: inputs => {
distPlusIngredients,
samplingInputs,
inputVariables,
environment,
};
};
@ -61,14 +63,27 @@ module Internals = {
type inputs = {
samplingInputs: Inputs.SamplingInputs.t,
guesstimatorString: string,
inputVariables: Belt.Map.String.t(ExpressionTypes.ExpressionTree.node),
environment: ExpressionTypes.ExpressionTree.environment,
};
let addVariable =
(
{samplingInputs, guesstimatorString, environment}: inputs,
str,
node,
)
: inputs => {
samplingInputs,
guesstimatorString,
environment:
ExpressionTypes.ExpressionTree.Environment.update(environment, str, _ => Some(node))
};
let distPlusRenderInputsToInputs = (inputs: Inputs.inputs): inputs => {
{
samplingInputs: inputs.samplingInputs,
guesstimatorString: inputs.distPlusIngredients.guesstimatorString,
inputVariables: inputs.inputVariables,
environment: inputs.environment,
};
};
@ -78,27 +93,46 @@ module Internals = {
};
let makeOutputs = (graph, shape): outputs => {graph, shape};
let inputsToShape = (inputs: inputs) => {
MathJsParser.fromString(inputs.guesstimatorString, inputs.inputVariables)
|> E.R.bind(_, g =>
let runNode = (inputs, node) => {
Js.log2("Inputs", inputs);
ExpressionTree.toShape(
{
sampleCount:
inputs.samplingInputs.sampleCount |> E.O.default(10000),
sampleCount: inputs.samplingInputs.sampleCount |> E.O.default(10000),
outputXYPoints:
inputs.samplingInputs.outputXYPoints |> E.O.default(10000),
kernelWidth: inputs.samplingInputs.kernelWidth,
shapeLength: inputs.samplingInputs.shapeLength |> E.O.default(10000)
shapeLength: inputs.samplingInputs.shapeLength |> E.O.default(10000),
},
g,
)
|> E.R.fmap(makeOutputs(g))
inputs.environment,
node,
);
};
let outputToDistPlus = (inputs: Inputs.inputs, outputs: outputs) => {
let runProgram = (inputs: inputs, p: ExpressionTypes.Program.program) => {
let ins = ref(inputs);
p
|> E.A.fmap(statement =>
switch (statement) {
| `Assignment(name, node) =>
ins := addVariable(ins^, name, node);
Js.log4("HIHI", ins, name, node);
None;
| `Expression(node) => Some(runNode(ins^, node))
}
)
|> E.A.O.concatSomes
|> E.A.R.firstErrorOrOpen;
};
let inputsToShape = (inputs: inputs) => {
MathJsParser.fromString(inputs.guesstimatorString, inputs.environment)
|> E.R.bind(_, g => runProgram(inputs, g))
|> E.R.bind(_, r => E.A.last(r) |> E.O.toResult("sdf"));
};
let outputToDistPlus = (inputs: Inputs.inputs, shape: DistTypes.shape) => {
DistPlus.make(
~shape=outputs.shape,
~shape,
~domain=inputs.distPlusIngredients.domain,
~unit=inputs.distPlusIngredients.unit,
~guesstimatorString=Some(inputs.distPlusIngredients.guesstimatorString),