2022-01-18 00:10:06 +00:00
|
|
|
// TODO: This setup is more confusing than it should be, there's more work to do in cleanup here.
|
|
|
|
module Inputs = {
|
|
|
|
module SamplingInputs = {
|
|
|
|
type t = {
|
|
|
|
sampleCount: option<int>,
|
|
|
|
outputXYPoints: option<int>,
|
|
|
|
kernelWidth: option<float>,
|
2022-02-27 04:25:30 +00:00
|
|
|
pointDistLength: option<int>,
|
2022-01-18 00:10:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
let defaultRecommendedLength = 100
|
|
|
|
let defaultShouldDownsample = true
|
|
|
|
|
|
|
|
type inputs = {
|
|
|
|
squiggleString: string,
|
|
|
|
samplingInputs: SamplingInputs.t,
|
2022-02-17 13:51:24 +00:00
|
|
|
environment: ASTTypes.environment,
|
2022-01-18 00:10:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let empty: SamplingInputs.t = {
|
|
|
|
sampleCount: None,
|
|
|
|
outputXYPoints: None,
|
|
|
|
kernelWidth: None,
|
2022-02-27 04:25:30 +00:00
|
|
|
pointDistLength: None,
|
2022-01-18 00:10:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let make = (
|
|
|
|
~samplingInputs=empty,
|
|
|
|
~squiggleString,
|
2022-02-17 13:51:24 +00:00
|
|
|
~environment=ASTTypes.Environment.empty,
|
2022-01-18 00:10:06 +00:00
|
|
|
(),
|
|
|
|
): inputs => {
|
|
|
|
samplingInputs: samplingInputs,
|
|
|
|
squiggleString: squiggleString,
|
|
|
|
environment: environment,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-22 02:33:28 +00:00
|
|
|
type exportDistribution = [
|
2022-02-08 02:59:37 +00:00
|
|
|
| #DistPlus(DistPlus.t)
|
2022-01-18 00:10:06 +00:00
|
|
|
| #Float(float)
|
2022-04-11 03:42:05 +00:00
|
|
|
| #Function(float => Belt.Result.t<DistPlus.t, string>)
|
2022-01-18 00:10:06 +00:00
|
|
|
]
|
|
|
|
|
2022-03-22 02:33:28 +00:00
|
|
|
type exportEnv = array<(string, ASTTypes.node)>
|
|
|
|
|
|
|
|
type exportType = {
|
2022-04-11 03:42:05 +00:00
|
|
|
environment: exportEnv,
|
|
|
|
exports: array<exportDistribution>,
|
2022-03-22 02:33:28 +00:00
|
|
|
}
|
|
|
|
|
2022-01-18 00:10:06 +00:00
|
|
|
module Internals = {
|
|
|
|
let addVariable = (
|
|
|
|
{samplingInputs, squiggleString, environment}: Inputs.inputs,
|
|
|
|
str,
|
|
|
|
node,
|
|
|
|
): Inputs.inputs => {
|
|
|
|
samplingInputs: samplingInputs,
|
|
|
|
squiggleString: squiggleString,
|
2022-04-11 03:42:05 +00:00
|
|
|
environment: ASTTypes.Environment.update(environment, str, _ => Some(node)),
|
2022-01-18 00:10:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type outputs = {
|
2022-02-17 13:51:24 +00:00
|
|
|
graph: ASTTypes.node,
|
2022-02-15 22:43:31 +00:00
|
|
|
pointSetDist: PointSetTypes.pointSetDist,
|
2022-01-18 00:10:06 +00:00
|
|
|
}
|
2022-02-27 04:25:30 +00:00
|
|
|
let makeOutputs = (graph, shape): outputs => {graph: graph, pointSetDist: shape}
|
2022-01-18 00:10:06 +00:00
|
|
|
|
2022-02-16 22:37:59 +00:00
|
|
|
let makeInputs = (inputs: Inputs.inputs): SamplingInputs.samplingInputs => {
|
2022-01-18 00:10:06 +00:00
|
|
|
sampleCount: inputs.samplingInputs.sampleCount |> E.O.default(10000),
|
|
|
|
outputXYPoints: inputs.samplingInputs.outputXYPoints |> E.O.default(10000),
|
|
|
|
kernelWidth: inputs.samplingInputs.kernelWidth,
|
2022-02-27 04:25:30 +00:00
|
|
|
pointSetDistLength: inputs.samplingInputs.pointDistLength |> E.O.default(10000),
|
2022-01-18 00:10:06 +00:00
|
|
|
}
|
|
|
|
|
2022-04-11 03:42:05 +00:00
|
|
|
let runNode = (inputs, node) => AST.toLeaf(makeInputs(inputs), inputs.environment, node)
|
2022-01-18 00:10:06 +00:00
|
|
|
|
2022-03-22 02:33:28 +00:00
|
|
|
let renderIfNeeded = (inputs: Inputs.inputs, node: ASTTypes.node): result<
|
|
|
|
ASTTypes.node,
|
|
|
|
string,
|
|
|
|
> =>
|
|
|
|
node |> (
|
|
|
|
x =>
|
|
|
|
switch x {
|
|
|
|
| #Normalize(_) as n
|
|
|
|
| #SymbolicDist(_) as n =>
|
|
|
|
#Render(n)
|
|
|
|
|> runNode(inputs)
|
|
|
|
|> (
|
|
|
|
x =>
|
|
|
|
switch x {
|
|
|
|
| Ok(#RenderedDist(_)) as r => r
|
|
|
|
| Error(r) => Error(r)
|
|
|
|
| _ => Error("Didn't render, but intended to")
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
| n => Ok(n)
|
|
|
|
}
|
2022-01-18 00:10:06 +00:00
|
|
|
)
|
|
|
|
|
2022-02-15 22:43:31 +00:00
|
|
|
let outputToDistPlus = (inputs: Inputs.inputs, pointSetDist: PointSetTypes.pointSetDist) =>
|
|
|
|
DistPlus.make(~pointSetDist, ~squiggleString=Some(inputs.squiggleString), ())
|
2022-01-18 00:10:06 +00:00
|
|
|
|
2022-04-11 03:42:05 +00:00
|
|
|
let rec returnDist = (
|
|
|
|
functionInfo: (array<string>, ASTTypes.node),
|
|
|
|
inputs: Inputs.inputs,
|
|
|
|
env: ASTTypes.environment,
|
|
|
|
) => {
|
|
|
|
(input: float) => {
|
|
|
|
let foo: Inputs.inputs = {...inputs, environment: env}
|
|
|
|
evaluateFunction(foo, functionInfo, [#SymbolicDist(#Float(input))]) |> E.R.bind(_, a =>
|
2022-03-22 02:33:28 +00:00
|
|
|
switch a {
|
|
|
|
| #DistPlus(d) => Ok(DistPlus.T.normalize(d))
|
|
|
|
| n =>
|
|
|
|
Js.log2("Error here", n)
|
|
|
|
Error("wrong type")
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// TODO: Consider using ExpressionTypes.ExpressionTree.getFloat or similar in this function
|
2022-04-11 03:42:05 +00:00
|
|
|
and coersionToExportedTypes = (inputs, env: ASTTypes.environment, ex: ASTTypes.node): result<
|
|
|
|
exportDistribution,
|
|
|
|
string,
|
|
|
|
> =>
|
2022-03-22 02:33:28 +00:00
|
|
|
ex
|
|
|
|
|> renderIfNeeded(inputs)
|
|
|
|
|> E.R.bind(_, x =>
|
2022-01-18 00:10:06 +00:00
|
|
|
switch x {
|
2022-03-22 02:33:28 +00:00
|
|
|
| #RenderedDist(Discrete({xyShape: {xs: [x], ys: [1.0]}})) => Ok(#Float(x))
|
|
|
|
| #SymbolicDist(#Float(x)) => Ok(#Float(x))
|
|
|
|
| #RenderedDist(n) => Ok(#DistPlus(outputToDistPlus(inputs, n)))
|
|
|
|
| #Function(n) => Ok(#Function(returnDist(n, inputs, env)))
|
|
|
|
| n => Error("Didn't output a rendered distribution. Format:" ++ AST.toString(n))
|
2022-02-27 04:25:30 +00:00
|
|
|
}
|
|
|
|
)
|
2022-01-18 00:10:06 +00:00
|
|
|
|
2022-04-11 03:42:05 +00:00
|
|
|
and evaluateFunction = (inputs: Inputs.inputs, fn: (array<string>, ASTTypes.node), fnInputs) => {
|
|
|
|
let output = AST.runFunction(makeInputs(inputs), inputs.environment, fnInputs, fn)
|
2022-03-22 02:33:28 +00:00
|
|
|
output |> E.R.bind(_, coersionToExportedTypes(inputs, inputs.environment))
|
|
|
|
}
|
2022-02-27 04:25:30 +00:00
|
|
|
|
2022-03-22 02:33:28 +00:00
|
|
|
let runProgram = (inputs: Inputs.inputs, p: ASTTypes.program) => {
|
|
|
|
let ins = ref(inputs)
|
|
|
|
p
|
2022-04-11 03:42:05 +00:00
|
|
|
|> E.A.fmap(x =>
|
|
|
|
switch x {
|
|
|
|
| #Assignment(name, node) =>
|
|
|
|
ins := addVariable(ins.contents, name, node)
|
|
|
|
None
|
|
|
|
| #Expression(node) => Some(runNode(ins.contents, node))
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|> E.A.O.concatSomes
|
|
|
|
|> E.A.R.firstErrorOrOpen
|
|
|
|
|> E.R.bind(_, d =>
|
|
|
|
d
|
|
|
|
|> E.A.fmap(x => coersionToExportedTypes(inputs, ins.contents.environment, x))
|
2022-03-22 02:33:28 +00:00
|
|
|
|> E.A.R.firstErrorOrOpen
|
2022-04-11 03:42:05 +00:00
|
|
|
)
|
|
|
|
|> E.R.fmap(ex => {
|
|
|
|
environment: Belt.Map.String.toArray(ins.contents.environment),
|
|
|
|
exports: ex,
|
|
|
|
})
|
2022-01-29 22:43:08 +00:00
|
|
|
}
|
2022-01-18 00:10:06 +00:00
|
|
|
|
2022-03-22 02:33:28 +00:00
|
|
|
let inputsToLeaf = (inputs: Inputs.inputs) =>
|
|
|
|
Parser.fromString(inputs.squiggleString) |> E.R.bind(_, g => runProgram(inputs, g))
|
|
|
|
}
|
2022-01-18 00:10:06 +00:00
|
|
|
|
2022-01-29 22:43:08 +00:00
|
|
|
@genType
|
2022-04-11 03:42:05 +00:00
|
|
|
let runAll: (string, Inputs.SamplingInputs.t, exportEnv) => result<exportType, string> = (
|
|
|
|
squiggleString,
|
|
|
|
samplingInputs,
|
|
|
|
environment,
|
|
|
|
) => {
|
2022-01-29 22:43:08 +00:00
|
|
|
let inputs = Inputs.make(
|
2022-03-01 07:43:35 +00:00
|
|
|
~samplingInputs,
|
2022-01-29 22:43:08 +00:00
|
|
|
~squiggleString,
|
2022-03-22 02:33:28 +00:00
|
|
|
~environment=Belt.Map.String.fromArray(environment),
|
2022-01-29 22:43:08 +00:00
|
|
|
(),
|
|
|
|
)
|
2022-03-22 02:33:28 +00:00
|
|
|
Internals.inputsToLeaf(inputs)
|
2022-01-29 22:43:08 +00:00
|
|
|
}
|