Added symbolic functions and tests for reducer interface distribution code

This commit is contained in:
Ozzie Gooen 2022-04-01 13:21:24 -04:00
parent 28eba9fa74
commit 18d742b63c
2 changed files with 74 additions and 4 deletions

View File

@ -0,0 +1,26 @@
open Jest
open Reducer_TestHelpers
let makeTest = (str, result) => test(str, () => expectEvalToBe(str, result))
describe("eval", () => {
Only.describe("expressions", () => {
makeTest("normal(5,2)", "Ok(Normal(5,2))")
makeTest("lognormal(5,2)", "Ok(Lognormal(5,2))")
makeTest("mean(normal(5,2))", "Ok(5)")
makeTest("mean(lognormal(1,2))", "Ok(20.085536923187668)")
makeTest("normalize(normal(5,2))", "Ok(Normal(5,2))")
makeTest("toPointSet(normal(5,2))", "Ok(Point Set Distribution)")
makeTest("toSampleSet(normal(5,2), 100)", "Ok(Sample Set Distribution)")
makeTest("add(normal(5,2), normal(10,2))", "Ok(Normal(15,2.8284271247461903))")
makeTest("add(normal(5,2), lognormal(10,2))", "Ok(Sample Set Distribution)")
makeTest("dotAdd(normal(5,2), lognormal(10,2))", "Ok(Point Set Distribution)")
makeTest("dotAdd(normal(5,2), 3)", "Ok(Point Set Distribution)")
makeTest("add(normal(5,2), 3)", "Ok(Point Set Distribution)")
makeTest("add(3, normal(5,2))", "Ok(Point Set Distribution)")
makeTest("3+normal(5,2)", "Ok(Point Set Distribution)")
makeTest("add(3, 3)", "Ok(6)")
makeTest("truncateLeft(normal(5,2), 3)", "Ok(Point Set Distribution)")
makeTest("mean(add(3, normal(5,2)))", "Ok(8.004619792609384)")
})
})

View File

@ -74,11 +74,54 @@ let genericOutputToReducerValue = (o: GenericDist_GenericOperation.outputType):
| GenDistError(Other(s)) => Error(RETodo(s)) | GenDistError(Other(s)) => Error(RETodo(s))
} }
module SymbolicConstructor = {
let oneFloat = name =>
switch name {
| "exponential" => Ok(SymbolicDist.Exponential.make)
| _ => Error("impossible path")
}
let twoFloat = name =>
switch name {
| "normal" => Ok(SymbolicDist.Normal.make)
| "uniform" => Ok(SymbolicDist.Uniform.make)
| "beta" => Ok(SymbolicDist.Beta.make)
| "lognormal" => Ok(SymbolicDist.Lognormal.make)
| _ => Error("impossible path")
}
let threeFloat = name =>
switch name {
| "triangular" => Ok(SymbolicDist.Triangular.make)
| _ => Error("impossible path")
}
let symbolicResultToOutput = (
symbolicResult: result<SymbolicDistTypes.symbolicDist, string>,
): option<GenericDist_GenericOperation.outputType> =>
switch symbolicResult {
| Ok(r) => Some(Dist(Symbolic(r)))
| Error(r) => Some(GenDistError(Other(r)))
}
}
let dispatchToGenericOutput = (call: ExpressionValue.functionCall): option< let dispatchToGenericOutput = (call: ExpressionValue.functionCall): option<
GenericDist_GenericOperation.outputType, GenericDist_GenericOperation.outputType,
> => { > => {
let (fnName, args) = call let (fnName, args) = call
switch (fnName, args) { switch (fnName, args) {
| ("exponential" as fnName, [EvNumber(f1)]) =>
SymbolicConstructor.oneFloat(fnName)
->E.R.bind(r => r(f1))
->SymbolicConstructor.symbolicResultToOutput
| (("normal" | "uniform" | "beta" | "lognormal") as fnName, [EvNumber(f1), EvNumber(f2)]) =>
SymbolicConstructor.twoFloat(fnName)
->E.R.bind(r => r(f1, f2))
->SymbolicConstructor.symbolicResultToOutput
| ("triangular" as fnName, [EvNumber(f1), EvNumber(f2), EvNumber(f3)]) =>
SymbolicConstructor.threeFloat(fnName)
->E.R.bind(r => r(f1, f2, f3))
->SymbolicConstructor.symbolicResultToOutput
| ("sample", [EvDistribution(dist)]) => toFloatFn(#Sample, dist) | ("sample", [EvDistribution(dist)]) => toFloatFn(#Sample, dist)
| ("mean", [EvDistribution(dist)]) => toFloatFn(#Mean, dist) | ("mean", [EvDistribution(dist)]) => toFloatFn(#Mean, dist)
| ("normalize", [EvDistribution(dist)]) => toDistFn(Normalize, dist) | ("normalize", [EvDistribution(dist)]) => toDistFn(Normalize, dist)
@ -88,20 +131,21 @@ let dispatchToGenericOutput = (call: ExpressionValue.functionCall): option<
| ("inv", [EvDistribution(dist), EvNumber(float)]) => toFloatFn(#Inv(float), dist) | ("inv", [EvDistribution(dist), EvNumber(float)]) => toFloatFn(#Inv(float), dist)
| ("toSampleSet", [EvDistribution(dist), EvNumber(float)]) => | ("toSampleSet", [EvDistribution(dist), EvNumber(float)]) =>
toDistFn(ToSampleSet(Belt.Int.fromFloat(float)), dist) toDistFn(ToSampleSet(Belt.Int.fromFloat(float)), dist)
| ("truncateLeft", [EvDistribution(dist), EvNumber(float)]) => toDistFn(Truncate(Some(float), None), dist) | ("truncateLeft", [EvDistribution(dist), EvNumber(float)]) =>
toDistFn(Truncate(Some(float), None), dist)
| ("truncateRight", [EvDistribution(dist), EvNumber(float)]) => | ("truncateRight", [EvDistribution(dist), EvNumber(float)]) =>
toDistFn(Truncate(None, Some(float)), dist) toDistFn(Truncate(None, Some(float)), dist)
| ("truncate", [EvDistribution(dist), EvNumber(float1), EvNumber(float2)]) => | ("truncate", [EvDistribution(dist), EvNumber(float1), EvNumber(float2)]) =>
toDistFn(Truncate(Some(float1), Some(float2)), dist) toDistFn(Truncate(Some(float1), Some(float2)), dist)
| (("add" | "multiply" | "subtract" | "divide" | "exponentiate") as arithmetic, [a, b] as args) => | (("add" | "multiply" | "subtract" | "divide" | "exponentiate") as arithmetic, [a, b] as args) =>
catchAndConvertTwoArgsToDists(args) -> E.O2.fmap(((fst, snd)) => catchAndConvertTwoArgsToDists(args)->E.O2.fmap(((fst, snd)) =>
twoDiststoDistFn(Algebraic, arithmetic, fst, snd) twoDiststoDistFn(Algebraic, arithmetic, fst, snd)
) )
| ( | (
("dotAdd" | "dotMultiply" | "dotSubtract" | "dotDivide" | "dotExponentiate") as arithmetic, ("dotAdd" | "dotMultiply" | "dotSubtract" | "dotDivide" | "dotExponentiate") as arithmetic,
[a, b] as args, [a, b] as args,
) => ) =>
catchAndConvertTwoArgsToDists(args) -> E.O2.fmap(((fst, snd)) => catchAndConvertTwoArgsToDists(args)->E.O2.fmap(((fst, snd)) =>
twoDiststoDistFn(Pointwise, arithmetic, fst, snd) twoDiststoDistFn(Pointwise, arithmetic, fst, snd)
) )
| _ => None | _ => None
@ -109,5 +153,5 @@ let dispatchToGenericOutput = (call: ExpressionValue.functionCall): option<
} }
let dispatch = call => { let dispatch = call => {
dispatchToGenericOutput(call) -> E.O2.fmap(genericOutputToReducerValue) dispatchToGenericOutput(call)->E.O2.fmap(genericOutputToReducerValue)
} }