Experiment with function registry for normal distribution

This commit is contained in:
Ozzie Gooen 2022-05-17 21:16:26 -04:00
parent f30de20c8d
commit 3085805a4d

View File

@ -1,7 +1,12 @@
type expressionValue = ReducerInterface_ExpressionValue.expressionValue type expressionValue = ReducerInterface_ExpressionValue.expressionValue
type rec itype = type rec itype =
I_Number | I_Numeric | I_DistOrNumber | I_Record(iRecord) | I_Array(array<itype>) | I_Option(itype) | I_Number
| I_Numeric
| I_DistOrNumber
| I_Record(iRecord)
| I_Array(array<itype>)
| I_Option(itype)
and iRecord = array<iRecordParam> and iRecord = array<iRecordParam>
and iRecordParam = (string, itype) and iRecordParam = (string, itype)
@ -14,7 +19,7 @@ type rec value =
and record = array<(string, value)> and record = array<(string, value)>
and distOrNumber = Number(float) | Dist(DistributionTypes.genericDist) and distOrNumber = Number(float) | Dist(DistributionTypes.genericDist)
type runFn = array<value> => result<ReducerInterface_ExpressionValue.expressionValue, string> type runFn = array<value> => result<expressionValue, string>
type fnDefinition = {name: string, inputs: array<itype>, run: runFn} type fnDefinition = {name: string, inputs: array<itype>, run: runFn}
@ -23,13 +28,25 @@ type function = {
definitions: array<fnDefinition>, definitions: array<fnDefinition>,
} }
module Function = {
let make = (name, definitions): function => {
name: name,
definitions: definitions,
}
let makeDefinition = (name, inputs, run): fnDefinition => {
name: name,
inputs: inputs,
run: run,
}
}
let rec matchInput = (input: itype, r: expressionValue): option<value> => let rec matchInput = (input: itype, r: expressionValue): option<value> =>
switch (input, r) { switch (input, r) {
| (I_Number, EvNumber(f)) => Some(Number(f)) | (I_Number, EvNumber(f)) => Some(Number(f))
| (I_DistOrNumber, EvNumber(f)) => Some(DistOrNumber(Number(f))) | (I_DistOrNumber, EvNumber(f)) => Some(DistOrNumber(Number(f)))
| (I_DistOrNumber, EvDistribution(f)) => Some(DistOrNumber(Dist(f))) | (I_DistOrNumber, EvDistribution(f)) => Some(DistOrNumber(Dist(f)))
| (I_Numeric, EvNumber(f)) => Some(Number(f)) | (I_Numeric, EvNumber(f)) => Some(Number(f))
| (I_Numeric, EvDistribution(Symbolic(#Float(f)))) => Some((Number(f))) | (I_Numeric, EvDistribution(Symbolic(#Float(f)))) => Some(Number(f))
| (I_Option(v), _) => Some(Option(matchInput(v, r))) | (I_Option(v), _) => Some(Option(matchInput(v, r)))
| (I_Record(recordParams), EvRecord(record)) => { | (I_Record(recordParams), EvRecord(record)) => {
let getAndMatch = (name, input) => let getAndMatch = (name, input) =>
@ -89,3 +106,46 @@ let match = (f: function, fnName: string, args: array<expressionValue>) => {
E.A.getByOpen(f.definitions, r => matchSingle(r, fnName, args), isNameMatchOnly) E.A.getByOpen(f.definitions, r => matchSingle(r, fnName, args), isNameMatchOnly)
E.A.O.firstSomeFnWithDefault([matchedDefinition, getMatchedNameOnlyDefinition], DifferentName) E.A.O.firstSomeFnWithDefault([matchedDefinition, getMatchedNameOnlyDefinition], DifferentName)
} }
let twoNumberInputs = (inputs: array<value>) =>
switch inputs {
| [Number(n1), Number(n2)] => Ok(n1, n2)
| _ => Error("Wrong inputs / Logically impossible")
}
let twoNumberInputsRecord = (v1, v2, inputs: array<value>) =>
switch inputs {
| [Record([(name1, n1), (name2, n2)])] if name1 == v1 && name2 == v2 => twoNumberInputs([n1, n2])
| _ => Error("Wrong inputs / Logically impossible")
}
let contain = r => ReducerInterface_ExpressionValue.EvDistribution(Symbolic(r))
let meanStdev = (mean, stdev) => SymbolicDist.Normal.make(mean, stdev)->E.R2.fmap(contain)
let p5and95 = (p5, p95) => contain(SymbolicDist.Normal.from90PercentCI(p5, p95))
let convertTwoInputs = (inputs: array<value>): result<expressionValue, string> =>
twoNumberInputs(inputs)->E.R.bind(((mean, stdev)) => meanStdev(mean, stdev))
let normal = Function.make(
"Normal",
[
Function.makeDefinition("normal", [I_Numeric, I_Numeric], inputs =>
twoNumberInputs(inputs)->E.R.bind(((mean, stdev)) => meanStdev(mean, stdev))
),
Function.makeDefinition(
"normal",
[I_Record([("mean", I_Numeric), ("stdev", I_Numeric)])],
inputs =>
twoNumberInputsRecord("mean", "stdev", inputs)->E.R.bind(((mean, stdev)) =>
meanStdev(mean, stdev)
),
),
Function.makeDefinition("normal", [I_Record([("p5", I_Numeric), ("p95", I_Numeric)])], inputs =>
twoNumberInputsRecord("p5", "p95", inputs)->E.R.bind(((mean, stdev)) =>
meanStdev(mean, stdev)
)
),
],
)