Touchups for FunctionRegistry distTwo

This commit is contained in:
Ozzie Gooen 2022-05-19 09:25:34 -04:00
parent 80a6c56efc
commit 50a5ef2498
4 changed files with 73 additions and 16 deletions

View File

@ -24,6 +24,7 @@ let isSymbolic = (t: t) =>
| _ => false | _ => false
} }
let sampleN = (t: t, n) => let sampleN = (t: t, n) =>
switch t { switch t {
| PointSet(r) => PointSetDist.sampleNRendered(n, r) | PointSet(r) => PointSetDist.sampleNRendered(n, r)
@ -31,6 +32,8 @@ let sampleN = (t: t, n) =>
| SampleSet(r) => SampleSetDist.sampleN(r, n) | SampleSet(r) => SampleSetDist.sampleN(r, n)
} }
let sample = (t: t) => sampleN(t, 1) -> E.A.first |> E.O.toExn("Should not have happened")
let toSampleSetDist = (t: t, n) => let toSampleSetDist = (t: t, n) =>
SampleSetDist.make(sampleN(t, n))->E.R2.errMap(DistributionTypes.Error.sampleErrorToDistErr) SampleSetDist.make(sampleN(t, n))->E.R2.errMap(DistributionTypes.Error.sampleErrorToDistErr)

View File

@ -6,6 +6,7 @@ type scaleMultiplyFn = (t, float) => result<t, error>
type pointwiseAddFn = (t, t) => result<t, error> type pointwiseAddFn = (t, t) => result<t, error>
let sampleN: (t, int) => array<float> let sampleN: (t, int) => array<float>
let sample: t => float
let toSampleSetDist: (t, int) => Belt.Result.t<QuriSquiggleLang.SampleSetDist.t, error> let toSampleSetDist: (t, int) => Belt.Result.t<QuriSquiggleLang.SampleSetDist.t, error>

View File

@ -34,6 +34,7 @@ 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(Symbolic(#Float(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))
@ -236,17 +237,19 @@ module Registry = {
} }
} }
let impossibleError = "Wrong inputs / Logically impossible"
let twoNumberInputs = (inputs: array<value>) => { let twoNumberInputs = (inputs: array<value>) => {
switch inputs { switch inputs {
| [Number(n1), Number(n2)] => Ok(n1, n2) | [Number(n1), Number(n2)] => Ok(n1, n2)
| _ => Error("Wrong inputs / Logically impossible") | _ => Error(impossibleError)
} }
} }
let twoNumberInputsRecord = (v1, v2, inputs: array<value>) => let twoNumberInputsRecord = (v1, v2, inputs: array<value>) =>
switch inputs { switch inputs {
| [Record([(name1, n1), (name2, n2)])] if name1 == v1 && name2 == v2 => twoNumberInputs([n1, n2]) | [Record([(name1, n1), (name2, n2)])] if name1 == v1 && name2 == v2 => twoNumberInputs([n1, n2])
| _ => Error("Wrong inputs / Logically impossible") | _ => Error(impossibleError)
} }
let contain = r => ReducerInterface_ExpressionValue.EvDistribution(Symbolic(r)) let contain = r => ReducerInterface_ExpressionValue.EvDistribution(Symbolic(r))
@ -258,24 +261,72 @@ let p5and95 = (p5, p95) => contain(SymbolicDist.Normal.from90PercentCI(p5, p95))
let convertTwoInputs = (inputs: array<value>): result<expressionValue, string> => let convertTwoInputs = (inputs: array<value>): result<expressionValue, string> =>
twoNumberInputs(inputs)->E.R.bind(((mean, stdev)) => meanStdev(mean, stdev)) twoNumberInputs(inputs)->E.R.bind(((mean, stdev)) => meanStdev(mean, stdev))
// let twoDistOrStdev = (a1:distOrNumber, a2:distOrNumber, fn) => { let twoDistOrStdev = (a1: value, a2: value) => {
// switch (a1, a2) { switch (a1, a2) {
// | (Number(a1), Number(a2)) => fn(a1, a2) | (DistOrNumber(a1), DistOrNumber(a2)) => Ok(a1, a2)
// | (Dist(a1), Number(a2)) => toSampleSetDist(a1, 1000)->sampleMap(r => fn(r, a2) |> sample) | _ => Error(impossibleError)
// | (Number(a1), Dist(a2)) => toSampleSetDist(a2, 1000)->sampleMap(r => fn(a1, r) |> sample) }
// | (Dist(a1), Dist(a2)) => SampleSetDist.map2(a1, a2, (m, s) => fn(m, s) |> sample) }
// }
// } let distTwo = (
~fn: (float, float) => result<DistributionTypes.genericDist, string>,
a1: value,
a2: value,
) => {
let toSampleSet = r => GenericDist.toSampleSetDist(r, 1000)
let sampleSetToExpressionValue = (
b: Belt.Result.t<QuriSquiggleLang.SampleSetDist.t, QuriSquiggleLang.DistributionTypes.error>,
) =>
switch b {
| Ok(r) => Ok(ReducerInterface_ExpressionValue.EvDistribution(SampleSet(r)))
| Error(d) => Error(DistributionTypes.Error.toString(d))
}
let mapFnResult = r =>
switch r {
| Ok(r) => Ok(GenericDist.sample(r))
| Error(r) => Error(Operation.Other(r))
}
let singleVarSample = (a, fn) => {
let sampleSetResult =
toSampleSet(a) |> E.R2.bind(dist =>
SampleSetDist.samplesMap(
~fn=f => fn(f)->mapFnResult,
dist,
)->E.R2.errMap(r => DistributionTypes.SampleSetError(r))
)
sampleSetResult->sampleSetToExpressionValue
}
switch (a1, a2) {
| (DistOrNumber(Number(a1)), DistOrNumber(Number(a2))) =>
fn(a1, a2)->E.R2.fmap(r => ReducerInterface_ExpressionValue.EvDistribution(r))
| (DistOrNumber(Dist(a1)), DistOrNumber(Number(a2))) => singleVarSample(a1, r => fn(r, a2))
| (DistOrNumber(Number(a1)), DistOrNumber(Dist(a2))) => singleVarSample(a2, r => fn(a1, r))
| (DistOrNumber(Dist(a1)), DistOrNumber(Dist(a2))) => {
let altFn = (a, b) => fn(a, b)->mapFnResult
let sampleSetResult =
E.R.merge(toSampleSet(a1), toSampleSet(a2))
->E.R2.errMap(DistributionTypes.Error.toString)
->E.R.bind(((t1, t2)) => {
SampleSetDist.map2(~fn=altFn, ~t1, ~t2)->E.R2.errMap(Operation.Error.toString)
})
->E.R2.errMap(r => DistributionTypes.OtherError(r))
sampleSetResult->sampleSetToExpressionValue
}
| _ => Error(impossibleError)
}
}
let normal = Function.make( let normal = Function.make(
"Normal", "Normal",
[ [
Function.makeDefinition("normal", [I_Numeric, I_Numeric], inputs => Function.makeDefinition("normal", [I_DistOrNumber, I_DistOrNumber], inputs => {
twoNumberInputs(inputs)->E.R.bind(((mean, stdev)) => meanStdev(mean, stdev)) let combine = (a1: float, a2: float) =>
), SymbolicDist.Normal.make(a1, a2)->E.R2.fmap(r => DistributionTypes.Symbolic(r))
Function.makeDefinition("normal", [I_DistOrNumber, I_DistOrNumber], inputs => distTwo(~fn=combine, inputs[0], inputs[1])
twoNumberInputs(inputs)->E.R.bind(((mean, stdev)) => meanStdev(mean, stdev)) }),
),
Function.makeDefinition( Function.makeDefinition(
"normal", "normal",
[I_Record([("mean", I_Numeric), ("stdev", I_Numeric)])], [I_Record([("mean", I_Numeric), ("stdev", I_Numeric)])],

View File

@ -58,6 +58,7 @@ type operationError =
| SampleMapNeedsNtoNFunction | SampleMapNeedsNtoNFunction
| PdfInvalidError | PdfInvalidError
| NotYetImplemented // should be removed when `klDivergence` for mixed and discrete is implemented. | NotYetImplemented // should be removed when `klDivergence` for mixed and discrete is implemented.
| Other(string)
@genType @genType
module Error = { module Error = {
@ -73,6 +74,7 @@ module Error = {
| SampleMapNeedsNtoNFunction => "SampleMap needs a function that converts a number to a number" | SampleMapNeedsNtoNFunction => "SampleMap needs a function that converts a number to a number"
| PdfInvalidError => "This Pdf is invalid" | PdfInvalidError => "This Pdf is invalid"
| NotYetImplemented => "This pathway is not yet implemented" | NotYetImplemented => "This pathway is not yet implemented"
| Other(t) => t
} }
} }