polymorphic variants to neatly constrain types

This commit is contained in:
Quinn Dougherty 2022-07-04 11:24:30 -04:00
parent 4858aa9fe5
commit 7889332052
8 changed files with 154 additions and 143 deletions

View File

@ -34,7 +34,7 @@ describe("sparkline", () => {
expected: DistributionOperation.outputType, expected: DistributionOperation.outputType,
) => { ) => {
test(name, () => { test(name, () => {
let result = DistributionOperation.run(~env, FromDist(ToString(ToSparkline(20)), dist)) let result = DistributionOperation.run(~env, FromDist(#ToString(ToSparkline(20)), dist))
expect(result)->toEqual(expected) expect(result)->toEqual(expected)
}) })
} }
@ -81,8 +81,8 @@ describe("sparkline", () => {
describe("toPointSet", () => { describe("toPointSet", () => {
test("on symbolic normal distribution", () => { test("on symbolic normal distribution", () => {
let result = let result =
run(FromDist(ToDist(ToPointSet), normalDist5)) run(FromDist(#ToDist(ToPointSet), normalDist5))
->outputMap(FromDist(ToFloat(#Mean))) ->outputMap(FromDist(#ToFloat(#Mean)))
->toFloat ->toFloat
->toExt ->toExt
expect(result)->toBeSoCloseTo(5.0, ~digits=0) expect(result)->toBeSoCloseTo(5.0, ~digits=0)
@ -90,10 +90,10 @@ describe("toPointSet", () => {
test("on sample set", () => { test("on sample set", () => {
let result = let result =
run(FromDist(ToDist(ToPointSet), normalDist5)) run(FromDist(#ToDist(ToPointSet), normalDist5))
->outputMap(FromDist(ToDist(ToSampleSet(1000)))) ->outputMap(FromDist(#ToDist(ToSampleSet(1000))))
->outputMap(FromDist(ToDist(ToPointSet))) ->outputMap(FromDist(#ToDist(ToPointSet)))
->outputMap(FromDist(ToFloat(#Mean))) ->outputMap(FromDist(#ToFloat(#Mean)))
->toFloat ->toFloat
->toExt ->toExt
expect(result)->toBeSoCloseTo(5.0, ~digits=-1) expect(result)->toBeSoCloseTo(5.0, ~digits=-1)

View File

@ -11,7 +11,7 @@ describe("mixture", () => {
let (mean1, mean2) = tup let (mean1, mean2) = tup
let meanValue = { let meanValue = {
run(Mixture([(mkNormal(mean1, 9e-1), 0.5), (mkNormal(mean2, 9e-1), 0.5)]))->outputMap( run(Mixture([(mkNormal(mean1, 9e-1), 0.5), (mkNormal(mean2, 9e-1), 0.5)]))->outputMap(
FromDist(ToFloat(#Mean)), FromDist(#ToFloat(#Mean)),
) )
} }
meanValue->unpackFloat->expect->toBeSoCloseTo((mean1 +. mean2) /. 2.0, ~digits=-1) meanValue->unpackFloat->expect->toBeSoCloseTo((mean1 +. mean2) /. 2.0, ~digits=-1)
@ -28,7 +28,7 @@ describe("mixture", () => {
let meanValue = { let meanValue = {
run( run(
Mixture([(mkBeta(alpha, beta), betaWeight), (mkExponential(rate), exponentialWeight)]), Mixture([(mkBeta(alpha, beta), betaWeight), (mkExponential(rate), exponentialWeight)]),
)->outputMap(FromDist(ToFloat(#Mean))) )->outputMap(FromDist(#ToFloat(#Mean)))
} }
let betaMean = 1.0 /. (1.0 +. beta /. alpha) let betaMean = 1.0 /. (1.0 +. beta /. alpha)
let exponentialMean = 1.0 /. rate let exponentialMean = 1.0 /. rate
@ -52,7 +52,7 @@ describe("mixture", () => {
(mkUniform(low, high), uniformWeight), (mkUniform(low, high), uniformWeight),
(mkLognormal(mu, sigma), lognormalWeight), (mkLognormal(mu, sigma), lognormalWeight),
]), ]),
)->outputMap(FromDist(ToFloat(#Mean))) )->outputMap(FromDist(#ToFloat(#Mean)))
} }
let uniformMean = (low +. high) /. 2.0 let uniformMean = (low +. high) /. 2.0
let lognormalMean = mu +. sigma ** 2.0 /. 2.0 let lognormalMean = mu +. sigma ** 2.0 /. 2.0

View File

@ -186,8 +186,8 @@ describe("combineAlongSupportOfSecondArgument0", () => {
uniformMakeR(lowPrediction, highPrediction)->E.R2.errMap(s => DistributionTypes.ArgumentError( uniformMakeR(lowPrediction, highPrediction)->E.R2.errMap(s => DistributionTypes.ArgumentError(
s, s,
)) ))
let answerWrapped = E.R.fmap(a => run(FromDist(ToDist(ToPointSet), a)), answer) let answerWrapped = E.R.fmap(a => run(FromDist(#ToDist(ToPointSet), a)), answer)
let predictionWrapped = E.R.fmap(a => run(FromDist(ToDist(ToPointSet), a)), prediction) let predictionWrapped = E.R.fmap(a => run(FromDist(#ToDist(ToPointSet), a)), prediction)
let interpolator = XYShape.XtoY.continuousInterpolator(#Stepwise, #UseZero) let interpolator = XYShape.XtoY.continuousInterpolator(#Stepwise, #UseZero)
let integrand = PointSetDist_Scoring.WithDistAnswer.integrand let integrand = PointSetDist_Scoring.WithDistAnswer.integrand

View File

@ -8,34 +8,34 @@ let mkNormal = (mean, stdev) => DistributionTypes.Symbolic(#Normal({mean: mean,
describe("(Symbolic) normalize", () => { describe("(Symbolic) normalize", () => {
testAll("has no impact on normal distributions", list{-1e8, -1e-2, 0.0, 1e-4, 1e16}, mean => { testAll("has no impact on normal distributions", list{-1e8, -1e-2, 0.0, 1e-4, 1e16}, mean => {
let normalValue = mkNormal(mean, 2.0) let normalValue = mkNormal(mean, 2.0)
let normalizedValue = run(FromDist(ToDist(Normalize), normalValue)) let normalizedValue = run(FromDist(#ToDist(Normalize), normalValue))
normalizedValue->unpackDist->expect->toEqual(normalValue) normalizedValue->unpackDist->expect->toEqual(normalValue)
}) })
}) })
describe("(Symbolic) mean", () => { describe("(Symbolic) mean", () => {
testAll("of normal distributions", list{-1e8, -16.0, -1e-2, 0.0, 1e-4, 32.0, 1e16}, mean => { testAll("of normal distributions", list{-1e8, -16.0, -1e-2, 0.0, 1e-4, 32.0, 1e16}, mean => {
run(FromDist(ToFloat(#Mean), mkNormal(mean, 4.0)))->unpackFloat->expect->toBeCloseTo(mean) run(FromDist(#ToFloat(#Mean), mkNormal(mean, 4.0)))->unpackFloat->expect->toBeCloseTo(mean)
}) })
Skip.test("of normal(0, -1) (it NaNs out)", () => { Skip.test("of normal(0, -1) (it NaNs out)", () => {
run(FromDist(ToFloat(#Mean), mkNormal(1e1, -1e0)))->unpackFloat->expect->ExpectJs.toBeFalsy run(FromDist(#ToFloat(#Mean), mkNormal(1e1, -1e0)))->unpackFloat->expect->ExpectJs.toBeFalsy
}) })
test("of normal(0, 1e-8) (it doesn't freak out at tiny stdev)", () => { test("of normal(0, 1e-8) (it doesn't freak out at tiny stdev)", () => {
run(FromDist(ToFloat(#Mean), mkNormal(0.0, 1e-8)))->unpackFloat->expect->toBeCloseTo(0.0) run(FromDist(#ToFloat(#Mean), mkNormal(0.0, 1e-8)))->unpackFloat->expect->toBeCloseTo(0.0)
}) })
testAll("of exponential distributions", list{1e-7, 2.0, 10.0, 100.0}, rate => { testAll("of exponential distributions", list{1e-7, 2.0, 10.0, 100.0}, rate => {
let meanValue = run( let meanValue = run(
FromDist(ToFloat(#Mean), DistributionTypes.Symbolic(#Exponential({rate: rate}))), FromDist(#ToFloat(#Mean), DistributionTypes.Symbolic(#Exponential({rate: rate}))),
) )
meanValue->unpackFloat->expect->toBeCloseTo(1.0 /. rate) // https://en.wikipedia.org/wiki/Exponential_distribution#Mean,_variance,_moments,_and_median meanValue->unpackFloat->expect->toBeCloseTo(1.0 /. rate) // https://en.wikipedia.org/wiki/Exponential_distribution#Mean,_variance,_moments,_and_median
}) })
test("of a cauchy distribution", () => { test("of a cauchy distribution", () => {
let meanValue = run( let meanValue = run(
FromDist(ToFloat(#Mean), DistributionTypes.Symbolic(#Cauchy({local: 1.0, scale: 1.0}))), FromDist(#ToFloat(#Mean), DistributionTypes.Symbolic(#Cauchy({local: 1.0, scale: 1.0}))),
) )
meanValue->unpackFloat->expect->toBeSoCloseTo(1.0098094001641797, ~digits=5) meanValue->unpackFloat->expect->toBeSoCloseTo(1.0098094001641797, ~digits=5)
//-> toBe(GenDistError(Other("Cauchy distributions may have no mean value."))) //-> toBe(GenDistError(Other("Cauchy distributions may have no mean value.")))
@ -48,7 +48,7 @@ describe("(Symbolic) mean", () => {
let (low, medium, high) = tup let (low, medium, high) = tup
let meanValue = run( let meanValue = run(
FromDist( FromDist(
ToFloat(#Mean), #ToFloat(#Mean),
DistributionTypes.Symbolic(#Triangular({low: low, medium: medium, high: high})), DistributionTypes.Symbolic(#Triangular({low: low, medium: medium, high: high})),
), ),
) )
@ -63,7 +63,7 @@ describe("(Symbolic) mean", () => {
tup => { tup => {
let (alpha, beta) = tup let (alpha, beta) = tup
let meanValue = run( let meanValue = run(
FromDist(ToFloat(#Mean), DistributionTypes.Symbolic(#Beta({alpha: alpha, beta: beta}))), FromDist(#ToFloat(#Mean), DistributionTypes.Symbolic(#Beta({alpha: alpha, beta: beta}))),
) )
meanValue->unpackFloat->expect->toBeCloseTo(1.0 /. (1.0 +. beta /. alpha)) // https://en.wikipedia.org/wiki/Beta_distribution#Mean meanValue->unpackFloat->expect->toBeCloseTo(1.0 /. (1.0 +. beta /. alpha)) // https://en.wikipedia.org/wiki/Beta_distribution#Mean
}, },
@ -72,7 +72,7 @@ describe("(Symbolic) mean", () => {
// TODO: When we have our theory of validators we won't want this to be NaN but to be an error. // TODO: When we have our theory of validators we won't want this to be NaN but to be an error.
test("of beta(0, 0)", () => { test("of beta(0, 0)", () => {
let meanValue = run( let meanValue = run(
FromDist(ToFloat(#Mean), DistributionTypes.Symbolic(#Beta({alpha: 0.0, beta: 0.0}))), FromDist(#ToFloat(#Mean), DistributionTypes.Symbolic(#Beta({alpha: 0.0, beta: 0.0}))),
) )
meanValue->unpackFloat->expect->ExpectJs.toBeFalsy meanValue->unpackFloat->expect->ExpectJs.toBeFalsy
}) })
@ -83,7 +83,7 @@ describe("(Symbolic) mean", () => {
tup => { tup => {
let (mu, sigma) = tup let (mu, sigma) = tup
let meanValue = run( let meanValue = run(
FromDist(ToFloat(#Mean), DistributionTypes.Symbolic(#Lognormal({mu: mu, sigma: sigma}))), FromDist(#ToFloat(#Mean), DistributionTypes.Symbolic(#Lognormal({mu: mu, sigma: sigma}))),
) )
meanValue->unpackFloat->expect->toBeCloseTo(Js.Math.exp(mu +. sigma ** 2.0 /. 2.0)) // https://brilliant.org/wiki/log-normal-distribution/ meanValue->unpackFloat->expect->toBeCloseTo(Js.Math.exp(mu +. sigma ** 2.0 /. 2.0)) // https://brilliant.org/wiki/log-normal-distribution/
}, },
@ -95,14 +95,14 @@ describe("(Symbolic) mean", () => {
tup => { tup => {
let (low, high) = tup let (low, high) = tup
let meanValue = run( let meanValue = run(
FromDist(ToFloat(#Mean), DistributionTypes.Symbolic(#Uniform({low: low, high: high}))), FromDist(#ToFloat(#Mean), DistributionTypes.Symbolic(#Uniform({low: low, high: high}))),
) )
meanValue->unpackFloat->expect->toBeCloseTo((low +. high) /. 2.0) // https://en.wikipedia.org/wiki/Continuous_uniform_distribution#Moments meanValue->unpackFloat->expect->toBeCloseTo((low +. high) /. 2.0) // https://en.wikipedia.org/wiki/Continuous_uniform_distribution#Moments
}, },
) )
test("of a float", () => { test("of a float", () => {
let meanValue = run(FromDist(ToFloat(#Mean), DistributionTypes.Symbolic(#Float(7.7)))) let meanValue = run(FromDist(#ToFloat(#Mean), DistributionTypes.Symbolic(#Float(7.7))))
meanValue->unpackFloat->expect->toBeCloseTo(7.7) meanValue->unpackFloat->expect->toBeCloseTo(7.7)
}) })
}) })

View File

@ -101,14 +101,14 @@ let rec run = (~env, functionCallInfo: functionCallInfo): outputType => {
} }
let toPointSetFn = r => { let toPointSetFn = r => {
switch reCall(~functionCallInfo=FromDist(ToDist(ToPointSet), r), ()) { switch reCall(~functionCallInfo=FromDist(#ToDist(ToPointSet), r), ()) {
| Dist(PointSet(p)) => Ok(p) | Dist(PointSet(p)) => Ok(p)
| e => Error(OutputLocal.toErrorOrUnreachable(e)) | e => Error(OutputLocal.toErrorOrUnreachable(e))
} }
} }
let toSampleSetFn = r => { let toSampleSetFn = r => {
switch reCall(~functionCallInfo=FromDist(ToDist(ToSampleSet(sampleCount)), r), ()) { switch reCall(~functionCallInfo=FromDist(#ToDist(ToSampleSet(sampleCount)), r), ()) {
| Dist(SampleSet(p)) => Ok(p) | Dist(SampleSet(p)) => Ok(p)
| e => Error(OutputLocal.toErrorOrUnreachable(e)) | e => Error(OutputLocal.toErrorOrUnreachable(e))
} }
@ -116,13 +116,13 @@ let rec run = (~env, functionCallInfo: functionCallInfo): outputType => {
let scaleMultiply = (r, weight) => let scaleMultiply = (r, weight) =>
reCall( reCall(
~functionCallInfo=FromDist(ToDistCombination(Pointwise, #Multiply, #Float(weight)), r), ~functionCallInfo=FromDist(#ToDistCombination(Pointwise, #Multiply, #Float(weight)), r),
(), (),
)->OutputLocal.toDistR )->OutputLocal.toDistR
let pointwiseAdd = (r1, r2) => let pointwiseAdd = (r1, r2) =>
reCall( reCall(
~functionCallInfo=FromDist(ToDistCombination(Pointwise, #Add, #Dist(r2)), r1), ~functionCallInfo=FromDist(#ToDistCombination(Pointwise, #Add, #Dist(r2)), r1),
(), (),
)->OutputLocal.toDistR )->OutputLocal.toDistR
@ -131,40 +131,40 @@ let rec run = (~env, functionCallInfo: functionCallInfo): outputType => {
dist: genericDist, dist: genericDist,
): outputType => { ): outputType => {
let response = switch subFnName { let response = switch subFnName {
| ToFloat(distToFloatOperation) => | #ToFloat(distToFloatOperation) =>
GenericDist.toFloatOperation(dist, ~toPointSetFn, ~distToFloatOperation) GenericDist.toFloatOperation(dist, ~toPointSetFn, ~distToFloatOperation)
->E.R2.fmap(r => Float(r)) ->E.R2.fmap(r => Float(r))
->OutputLocal.fromResult ->OutputLocal.fromResult
| ToString(ToString) => dist->GenericDist.toString->String | #ToString(ToString) => dist->GenericDist.toString->String
| ToString(ToSparkline(bucketCount)) => | #ToString(ToSparkline(bucketCount)) =>
GenericDist.toSparkline(dist, ~sampleCount, ~bucketCount, ()) GenericDist.toSparkline(dist, ~sampleCount, ~bucketCount, ())
->E.R2.fmap(r => String(r)) ->E.R2.fmap(r => String(r))
->OutputLocal.fromResult ->OutputLocal.fromResult
| ToDist(Inspect) => { | #ToDist(Inspect) => {
Js.log2("Console log requested: ", dist) Js.log2("Console log requested: ", dist)
Dist(dist) Dist(dist)
} }
| ToDist(Normalize) => dist->GenericDist.normalize->Dist | #ToDist(Normalize) => dist->GenericDist.normalize->Dist
| ToScore(LogScore(answer, prior)) => | #ToScore(LogScore(answer, prior)) =>
GenericDist.Score.logScore(~estimate=Score_Dist(dist), ~answer, ~prior) GenericDist.Score.logScore(~estimate=Score_Dist(dist), ~answer, ~prior)
->E.R2.fmap(s => Float(s)) ->E.R2.fmap(s => Float(s))
->OutputLocal.fromResult ->OutputLocal.fromResult
| ToBool(IsNormalized) => dist->GenericDist.isNormalized->Bool | #ToBool(IsNormalized) => dist->GenericDist.isNormalized->Bool
| ToDist(Truncate(leftCutoff, rightCutoff)) => | #ToDist(Truncate(leftCutoff, rightCutoff)) =>
GenericDist.truncate(~toPointSetFn, ~leftCutoff, ~rightCutoff, dist, ()) GenericDist.truncate(~toPointSetFn, ~leftCutoff, ~rightCutoff, dist, ())
->E.R2.fmap(r => Dist(r)) ->E.R2.fmap(r => Dist(r))
->OutputLocal.fromResult ->OutputLocal.fromResult
| ToDist(ToSampleSet(n)) => | #ToDist(ToSampleSet(n)) =>
dist dist
->GenericDist.toSampleSetDist(n) ->GenericDist.toSampleSetDist(n)
->E.R2.fmap(r => Dist(SampleSet(r))) ->E.R2.fmap(r => Dist(SampleSet(r)))
->OutputLocal.fromResult ->OutputLocal.fromResult
| ToDist(ToPointSet) => | #ToDist(ToPointSet) =>
dist dist
->GenericDist.toPointSet(~xyPointLength, ~sampleCount, ()) ->GenericDist.toPointSet(~xyPointLength, ~sampleCount, ())
->E.R2.fmap(r => Dist(PointSet(r))) ->E.R2.fmap(r => Dist(PointSet(r)))
->OutputLocal.fromResult ->OutputLocal.fromResult
| ToDist(Scale(#LogarithmWithThreshold(eps), f)) => | #ToDist(Scale(#LogarithmWithThreshold(eps), f)) =>
dist dist
->GenericDist.pointwiseCombinationFloat( ->GenericDist.pointwiseCombinationFloat(
~toPointSetFn, ~toPointSetFn,
@ -173,23 +173,23 @@ let rec run = (~env, functionCallInfo: functionCallInfo): outputType => {
) )
->E.R2.fmap(r => Dist(r)) ->E.R2.fmap(r => Dist(r))
->OutputLocal.fromResult ->OutputLocal.fromResult
| ToDist(Scale(#Multiply, f)) => | #ToDist(Scale(#Multiply, f)) =>
dist dist
->GenericDist.pointwiseCombinationFloat(~toPointSetFn, ~algebraicCombination=#Multiply, ~f) ->GenericDist.pointwiseCombinationFloat(~toPointSetFn, ~algebraicCombination=#Multiply, ~f)
->E.R2.fmap(r => Dist(r)) ->E.R2.fmap(r => Dist(r))
->OutputLocal.fromResult ->OutputLocal.fromResult
| ToDist(Scale(#Logarithm, f)) => | #ToDist(Scale(#Logarithm, f)) =>
dist dist
->GenericDist.pointwiseCombinationFloat(~toPointSetFn, ~algebraicCombination=#Logarithm, ~f) ->GenericDist.pointwiseCombinationFloat(~toPointSetFn, ~algebraicCombination=#Logarithm, ~f)
->E.R2.fmap(r => Dist(r)) ->E.R2.fmap(r => Dist(r))
->OutputLocal.fromResult ->OutputLocal.fromResult
| ToDist(Scale(#Power, f)) => | #ToDist(Scale(#Power, f)) =>
dist dist
->GenericDist.pointwiseCombinationFloat(~toPointSetFn, ~algebraicCombination=#Power, ~f) ->GenericDist.pointwiseCombinationFloat(~toPointSetFn, ~algebraicCombination=#Power, ~f)
->E.R2.fmap(r => Dist(r)) ->E.R2.fmap(r => Dist(r))
->OutputLocal.fromResult ->OutputLocal.fromResult
| ToDistCombination(Algebraic(_), _, #Float(_)) => GenDistError(NotYetImplemented) | #ToDistCombination(Algebraic(_), _, #Float(_)) => GenDistError(NotYetImplemented)
| ToDistCombination(Algebraic(strategy), arithmeticOperation, #Dist(t2)) => | #ToDistCombination(Algebraic(strategy), arithmeticOperation, #Dist(t2)) =>
dist dist
->GenericDist.algebraicCombination( ->GenericDist.algebraicCombination(
~strategy, ~strategy,
@ -200,12 +200,12 @@ let rec run = (~env, functionCallInfo: functionCallInfo): outputType => {
) )
->E.R2.fmap(r => Dist(r)) ->E.R2.fmap(r => Dist(r))
->OutputLocal.fromResult ->OutputLocal.fromResult
| ToDistCombination(Pointwise, algebraicCombination, #Dist(t2)) => | #ToDistCombination(Pointwise, algebraicCombination, #Dist(t2)) =>
dist dist
->GenericDist.pointwiseCombination(~toPointSetFn, ~algebraicCombination, ~t2) ->GenericDist.pointwiseCombination(~toPointSetFn, ~algebraicCombination, ~t2)
->E.R2.fmap(r => Dist(r)) ->E.R2.fmap(r => Dist(r))
->OutputLocal.fromResult ->OutputLocal.fromResult
| ToDistCombination(Pointwise, algebraicCombination, #Float(f)) => | #ToDistCombination(Pointwise, algebraicCombination, #Float(f)) =>
dist dist
->GenericDist.pointwiseCombinationFloat(~toPointSetFn, ~algebraicCombination, ~f) ->GenericDist.pointwiseCombinationFloat(~toPointSetFn, ~algebraicCombination, ~f)
->E.R2.fmap(r => Dist(r)) ->E.R2.fmap(r => Dist(r))
@ -216,8 +216,7 @@ let rec run = (~env, functionCallInfo: functionCallInfo): outputType => {
switch functionCallInfo { switch functionCallInfo {
| FromDist(subFnName, dist) => fromDistFn(subFnName, dist) | FromDist(subFnName, dist) => fromDistFn(subFnName, dist)
| FromFloat(subFnName, float) => | FromFloat(subFnName, x) => reCall(~functionCallInfo=FromFloat(subFnName, x), ())
reCall(~functionCallInfo=FromDist(subFnName, GenericDist.fromFloat(float)), ())
| Mixture(dists) => | Mixture(dists) =>
dists dists
->GenericDist.mixture(~scaleMultiplyFn=scaleMultiply, ~pointwiseAddFn=pointwiseAdd) ->GenericDist.mixture(~scaleMultiplyFn=scaleMultiply, ~pointwiseAddFn=pointwiseAdd)

View File

@ -27,7 +27,7 @@ let runFromDist: (
) => outputType ) => outputType
let runFromFloat: ( let runFromFloat: (
~env: env, ~env: env,
~functionCallInfo: DistributionTypes.DistributionOperation.fromDist, ~functionCallInfo: DistributionTypes.DistributionOperation.fromFloat,
float, float,
) => outputType ) => outputType

View File

@ -102,58 +102,82 @@ module DistributionOperation = {
type toScore = LogScore(genericDistOrScalar, option<genericDistOrScalar>) type toScore = LogScore(genericDistOrScalar, option<genericDistOrScalar>)
type fromDist = type fromFloat = [
| ToFloat(toFloat) | #ToFloat(toFloat)
| ToDist(toDist) | #ToDist(toDist)
| ToScore(toScore) | #ToDistCombination(direction, Operation.Algebraic.t, [#Dist(genericDist) | #Float(float)])
| ToDistCombination(direction, Operation.Algebraic.t, [#Dist(genericDist) | #Float(float)]) | #ToString(toString)
| ToString(toString) | #ToBool(toBool)
| ToBool(toBool) ]
type fromDist = [
| fromFloat
| #ToScore(toScore)
]
type singleParamaterFunction = type singleParamaterFunction =
| FromDist(fromDist) | FromDist(fromDist)
| FromFloat(fromDist) | FromFloat(fromFloat)
type genericFunctionCallInfo = type genericFunctionCallInfo =
| FromDist(fromDist, genericDist) | FromDist(fromDist, genericDist)
| FromFloat(fromDist, float) | FromFloat(fromFloat, float)
| FromSamples(array<float>) | FromSamples(array<float>)
| Mixture(array<(genericDist, float)>) | Mixture(array<(genericDist, float)>)
let distCallToString = (distFunction: fromDist): string => let floatCallToString = (floatFunction: fromFloat): string =>
switch distFunction { switch floatFunction {
| ToFloat(#Cdf(r)) => `cdf(${E.Float.toFixed(r)})` | #ToFloat(#Cdf(r)) => `cdf(${E.Float.toFixed(r)})`
| ToFloat(#Inv(r)) => `inv(${E.Float.toFixed(r)})` | #ToFloat(#Inv(r)) => `inv(${E.Float.toFixed(r)})`
| ToFloat(#Mean) => `mean` | #ToFloat(#Mean) => `mean`
| ToFloat(#Min) => `min` | #ToFloat(#Min) => `min`
| ToFloat(#Max) => `max` | #ToFloat(#Max) => `max`
| ToFloat(#Stdev) => `stdev` | #ToFloat(#Stdev) => `stdev`
| ToFloat(#Variance) => `variance` | #ToFloat(#Variance) => `variance`
| ToFloat(#Mode) => `mode` | #ToFloat(#Mode) => `mode`
| ToFloat(#Pdf(r)) => `pdf(${E.Float.toFixed(r)})` | #ToFloat(#Pdf(r)) => `pdf(${E.Float.toFixed(r)})`
| ToFloat(#Sample) => `sample` | #ToFloat(#Sample) => `sample`
| ToFloat(#IntegralSum) => `integralSum` | #ToFloat(#IntegralSum) => `integralSum`
| ToScore(_) => `logScore` | #ToDist(Normalize) => `normalize`
| ToDist(Normalize) => `normalize` | #ToDist(ToPointSet) => `toPointSet`
| ToDist(ToPointSet) => `toPointSet` | #ToDist(ToSampleSet(r)) => `toSampleSet(${E.I.toString(r)})`
| ToDist(ToSampleSet(r)) => `toSampleSet(${E.I.toString(r)})` | #ToDist(Truncate(_, _)) => `truncate`
| ToDist(Truncate(_, _)) => `truncate` | #ToDist(Inspect) => `inspect`
| ToDist(Inspect) => `inspect` | #ToDist(Scale(#Power, r)) => `scalePower(${E.Float.toFixed(r)})`
| ToDist(Scale(#Power, r)) => `scalePower(${E.Float.toFixed(r)})` | #ToDist(Scale(#Multiply, r)) => `scaleMultiply(${E.Float.toFixed(r)})`
| ToDist(Scale(#Multiply, r)) => `scaleMultiply(${E.Float.toFixed(r)})` | #ToDist(Scale(#Logarithm, r)) => `scaleLog(${E.Float.toFixed(r)})`
| ToDist(Scale(#Logarithm, r)) => `scaleLog(${E.Float.toFixed(r)})` | #ToDist(Scale(#LogarithmWithThreshold(eps), r)) =>
| ToDist(Scale(#LogarithmWithThreshold(eps), r)) =>
`scaleLogWithThreshold(${E.Float.toFixed(r)}, epsilon=${E.Float.toFixed(eps)})` `scaleLogWithThreshold(${E.Float.toFixed(r)}, epsilon=${E.Float.toFixed(eps)})`
| ToString(ToString) => `toString` | #ToString(ToString) => `toString`
| ToString(ToSparkline(n)) => `sparkline(${E.I.toString(n)})` | #ToString(ToSparkline(n)) => `sparkline(${E.I.toString(n)})`
| ToBool(IsNormalized) => `isNormalized` | #ToBool(IsNormalized) => `isNormalized`
| ToDistCombination(Algebraic(_), _, _) => `algebraic` | #ToDistCombination(Algebraic(_), _, _) => `algebraic`
| ToDistCombination(Pointwise, _, _) => `pointwise` | #ToDistCombination(Pointwise, _, _) => `pointwise`
}
let distCallToString = (
distFunction: [
| #ToFloat(toFloat)
| #ToDist(toDist)
| #ToDistCombination(direction, Operation.Algebraic.t, [#Dist(genericDist) | #Float(float)])
| #ToString(toString)
| #ToBool(toBool)
| #ToScore(toScore)
],
): string =>
switch distFunction {
| #ToScore(_) => `logScore`
| #ToFloat(x) => floatCallToString(#ToFloat(x))
| #ToDist(x) => floatCallToString(#ToDist(x))
| #ToString(x) => floatCallToString(#ToString(x))
| #ToBool(x) => floatCallToString(#ToBool(x))
| #ToDistCombination(x, y, z) => floatCallToString(#ToDistCombination(x, y, z))
} }
let toString = (d: genericFunctionCallInfo): string => let toString = (d: genericFunctionCallInfo): string =>
switch d { switch d {
| FromDist(f, _) | FromFloat(f, _) => distCallToString(f) | FromDist(f, _) => distCallToString(f)
| FromFloat(f, _) => floatCallToString(f)
| Mixture(_) => `mixture` | Mixture(_) => `mixture`
| FromSamples(_) => `fromSamples` | FromSamples(_) => `fromSamples`
} }
@ -163,93 +187,93 @@ module Constructors = {
module UsingDists = { module UsingDists = {
@genType @genType
let mean = (dist): t => FromDist(ToFloat(#Mean), dist) let mean = (dist): t => FromDist(#ToFloat(#Mean), dist)
let stdev = (dist): t => FromDist(ToFloat(#Stdev), dist) let stdev = (dist): t => FromDist(#ToFloat(#Stdev), dist)
let variance = (dist): t => FromDist(ToFloat(#Variance), dist) let variance = (dist): t => FromDist(#ToFloat(#Variance), dist)
let sample = (dist): t => FromDist(ToFloat(#Sample), dist) let sample = (dist): t => FromDist(#ToFloat(#Sample), dist)
let cdf = (dist, x): t => FromDist(ToFloat(#Cdf(x)), dist) let cdf = (dist, x): t => FromDist(#ToFloat(#Cdf(x)), dist)
let inv = (dist, x): t => FromDist(ToFloat(#Inv(x)), dist) let inv = (dist, x): t => FromDist(#ToFloat(#Inv(x)), dist)
let pdf = (dist, x): t => FromDist(ToFloat(#Pdf(x)), dist) let pdf = (dist, x): t => FromDist(#ToFloat(#Pdf(x)), dist)
let normalize = (dist): t => FromDist(ToDist(Normalize), dist) let normalize = (dist): t => FromDist(#ToDist(Normalize), dist)
let isNormalized = (dist): t => FromDist(ToBool(IsNormalized), dist) let isNormalized = (dist): t => FromDist(#ToBool(IsNormalized), dist)
let toPointSet = (dist): t => FromDist(ToDist(ToPointSet), dist) let toPointSet = (dist): t => FromDist(#ToDist(ToPointSet), dist)
let toSampleSet = (dist, r): t => FromDist(ToDist(ToSampleSet(r)), dist) let toSampleSet = (dist, r): t => FromDist(#ToDist(ToSampleSet(r)), dist)
let fromSamples = (xs): t => FromSamples(xs) let fromSamples = (xs): t => FromSamples(xs)
let truncate = (dist, left, right): t => FromDist(ToDist(Truncate(left, right)), dist) let truncate = (dist, left, right): t => FromDist(#ToDist(Truncate(left, right)), dist)
let inspect = (dist): t => FromDist(ToDist(Inspect), dist) let inspect = (dist): t => FromDist(#ToDist(Inspect), dist)
module LogScore = { module LogScore = {
let distEstimateDistAnswer = (estimate, answer): t => FromDist( let distEstimateDistAnswer = (estimate, answer): t => FromDist(
ToScore(LogScore(Score_Dist(answer), None)), #ToScore(LogScore(Score_Dist(answer), None)),
estimate, estimate,
) )
let distEstimateDistAnswerWithPrior = (estimate, answer, prior): t => FromDist( let distEstimateDistAnswerWithPrior = (estimate, answer, prior): t => FromDist(
ToScore(LogScore(Score_Dist(answer), Some(prior))), #ToScore(LogScore(Score_Dist(answer), Some(prior))),
estimate, estimate,
) )
let distEstimateScalarAnswer = (estimate, answer): t => FromDist( let distEstimateScalarAnswer = (estimate, answer): t => FromDist(
ToScore(LogScore(Score_Scalar(answer), None)), #ToScore(LogScore(Score_Scalar(answer), None)),
estimate, estimate,
) )
let distEstimateScalarAnswerWithPrior = (estimate, answer, prior): t => FromDist( let distEstimateScalarAnswerWithPrior = (estimate, answer, prior): t => FromDist(
ToScore(LogScore(Score_Scalar(answer), Some(prior))), #ToScore(LogScore(Score_Scalar(answer), Some(prior))),
estimate, estimate,
) )
} }
let scaleMultiply = (dist, n): t => FromDist(ToDist(Scale(#Multiply, n)), dist) let scaleMultiply = (dist, n): t => FromDist(#ToDist(Scale(#Multiply, n)), dist)
let scalePower = (dist, n): t => FromDist(ToDist(Scale(#Power, n)), dist) let scalePower = (dist, n): t => FromDist(#ToDist(Scale(#Power, n)), dist)
let scaleLogarithm = (dist, n): t => FromDist(ToDist(Scale(#Logarithm, n)), dist) let scaleLogarithm = (dist, n): t => FromDist(#ToDist(Scale(#Logarithm, n)), dist)
let scaleLogarithmWithThreshold = (dist, n, eps): t => FromDist( let scaleLogarithmWithThreshold = (dist, n, eps): t => FromDist(
ToDist(Scale(#LogarithmWithThreshold(eps), n)), #ToDist(Scale(#LogarithmWithThreshold(eps), n)),
dist, dist,
) )
let toString = (dist): t => FromDist(ToString(ToString), dist) let toString = (dist): t => FromDist(#ToString(ToString), dist)
let toSparkline = (dist, n): t => FromDist(ToString(ToSparkline(n)), dist) let toSparkline = (dist, n): t => FromDist(#ToString(ToSparkline(n)), dist)
let algebraicAdd = (dist1, dist2: genericDist): t => FromDist( let algebraicAdd = (dist1, dist2: genericDist): t => FromDist(
ToDistCombination(Algebraic(AsDefault), #Add, #Dist(dist2)), #ToDistCombination(Algebraic(AsDefault), #Add, #Dist(dist2)),
dist1, dist1,
) )
let algebraicMultiply = (dist1, dist2): t => FromDist( let algebraicMultiply = (dist1, dist2): t => FromDist(
ToDistCombination(Algebraic(AsDefault), #Multiply, #Dist(dist2)), #ToDistCombination(Algebraic(AsDefault), #Multiply, #Dist(dist2)),
dist1, dist1,
) )
let algebraicDivide = (dist1, dist2): t => FromDist( let algebraicDivide = (dist1, dist2): t => FromDist(
ToDistCombination(Algebraic(AsDefault), #Divide, #Dist(dist2)), #ToDistCombination(Algebraic(AsDefault), #Divide, #Dist(dist2)),
dist1, dist1,
) )
let algebraicSubtract = (dist1, dist2): t => FromDist( let algebraicSubtract = (dist1, dist2): t => FromDist(
ToDistCombination(Algebraic(AsDefault), #Subtract, #Dist(dist2)), #ToDistCombination(Algebraic(AsDefault), #Subtract, #Dist(dist2)),
dist1, dist1,
) )
let algebraicLogarithm = (dist1, dist2): t => FromDist( let algebraicLogarithm = (dist1, dist2): t => FromDist(
ToDistCombination(Algebraic(AsDefault), #Logarithm, #Dist(dist2)), #ToDistCombination(Algebraic(AsDefault), #Logarithm, #Dist(dist2)),
dist1, dist1,
) )
let algebraicPower = (dist1, dist2): t => FromDist( let algebraicPower = (dist1, dist2): t => FromDist(
ToDistCombination(Algebraic(AsDefault), #Power, #Dist(dist2)), #ToDistCombination(Algebraic(AsDefault), #Power, #Dist(dist2)),
dist1, dist1,
) )
let pointwiseAdd = (dist1, dist2): t => FromDist( let pointwiseAdd = (dist1, dist2): t => FromDist(
ToDistCombination(Pointwise, #Add, #Dist(dist2)), #ToDistCombination(Pointwise, #Add, #Dist(dist2)),
dist1, dist1,
) )
let pointwiseMultiply = (dist1, dist2): t => FromDist( let pointwiseMultiply = (dist1, dist2): t => FromDist(
ToDistCombination(Pointwise, #Multiply, #Dist(dist2)), #ToDistCombination(Pointwise, #Multiply, #Dist(dist2)),
dist1, dist1,
) )
let pointwiseDivide = (dist1, dist2): t => FromDist( let pointwiseDivide = (dist1, dist2): t => FromDist(
ToDistCombination(Pointwise, #Divide, #Dist(dist2)), #ToDistCombination(Pointwise, #Divide, #Dist(dist2)),
dist1, dist1,
) )
let pointwiseSubtract = (dist1, dist2): t => FromDist( let pointwiseSubtract = (dist1, dist2): t => FromDist(
ToDistCombination(Pointwise, #Subtract, #Dist(dist2)), #ToDistCombination(Pointwise, #Subtract, #Dist(dist2)),
dist1, dist1,
) )
let pointwiseLogarithm = (dist1, dist2): t => FromDist( let pointwiseLogarithm = (dist1, dist2): t => FromDist(
ToDistCombination(Pointwise, #Logarithm, #Dist(dist2)), #ToDistCombination(Pointwise, #Logarithm, #Dist(dist2)),
dist1, dist1,
) )
let pointwisePower = (dist1, dist2): t => FromDist( let pointwisePower = (dist1, dist2): t => FromDist(
ToDistCombination(Pointwise, #Power, #Dist(dist2)), #ToDistCombination(Pointwise, #Power, #Dist(dist2)),
dist1, dist1,
) )
} }

View File

@ -34,9 +34,7 @@ module Helpers = {
dist: DistributionTypes.genericDist, dist: DistributionTypes.genericDist,
~env: DistributionOperation.env, ~env: DistributionOperation.env,
) => { ) => {
FromDist(DistributionTypes.DistributionOperation.ToFloat(fnCall), dist) FromDist(#ToFloat(fnCall), dist)->DistributionOperation.run(~env)->Some
->DistributionOperation.run(~env)
->Some
} }
let toStringFn = ( let toStringFn = (
@ -44,9 +42,7 @@ module Helpers = {
dist: DistributionTypes.genericDist, dist: DistributionTypes.genericDist,
~env: DistributionOperation.env, ~env: DistributionOperation.env,
) => { ) => {
FromDist(DistributionTypes.DistributionOperation.ToString(fnCall), dist) FromDist(#ToString(fnCall), dist)->DistributionOperation.run(~env)->Some
->DistributionOperation.run(~env)
->Some
} }
let toBoolFn = ( let toBoolFn = (
@ -54,9 +50,7 @@ module Helpers = {
dist: DistributionTypes.genericDist, dist: DistributionTypes.genericDist,
~env: DistributionOperation.env, ~env: DistributionOperation.env,
) => { ) => {
FromDist(DistributionTypes.DistributionOperation.ToBool(fnCall), dist) FromDist(#ToBool(fnCall), dist)->DistributionOperation.run(~env)->Some
->DistributionOperation.run(~env)
->Some
} }
let toDistFn = ( let toDistFn = (
@ -64,18 +58,12 @@ module Helpers = {
dist, dist,
~env: DistributionOperation.env, ~env: DistributionOperation.env,
) => { ) => {
FromDist(DistributionTypes.DistributionOperation.ToDist(fnCall), dist) FromDist(#ToDist(fnCall), dist)->DistributionOperation.run(~env)->Some
->DistributionOperation.run(~env)
->Some
} }
let twoDiststoDistFn = (direction, arithmetic, dist1, dist2, ~env: DistributionOperation.env) => { let twoDiststoDistFn = (direction, arithmetic, dist1, dist2, ~env: DistributionOperation.env) => {
FromDist( FromDist(
DistributionTypes.DistributionOperation.ToDistCombination( #ToDistCombination(direction, arithmeticMap(arithmetic), #Dist(dist2)),
direction,
arithmeticMap(arithmetic),
#Dist(dist2),
),
dist1, dist1,
)->DistributionOperation.run(~env) )->DistributionOperation.run(~env)
} }
@ -229,7 +217,7 @@ let dispatchToGenericOutput = (call: IEV.functionCall, env: DistributionOperatio
Some( Some(
DistributionOperation.run( DistributionOperation.run(
FromDist( FromDist(
ToScore(LogScore(DistributionTypes.DistributionOperation.Score_Dist(answer), None)), #ToScore(LogScore(DistributionTypes.DistributionOperation.Score_Dist(answer), None)),
prediction, prediction,
), ),
~env, ~env,
@ -242,7 +230,7 @@ let dispatchToGenericOutput = (call: IEV.functionCall, env: DistributionOperatio
Some( Some(
DistributionOperation.run( DistributionOperation.run(
FromDist( FromDist(
ToScore( #ToScore(
LogScore( LogScore(
DistributionTypes.DistributionOperation.Score_Dist(answer), DistributionTypes.DistributionOperation.Score_Dist(answer),
Some(DistributionTypes.DistributionOperation.Score_Dist(prior)), Some(DistributionTypes.DistributionOperation.Score_Dist(prior)),
@ -267,7 +255,7 @@ let dispatchToGenericOutput = (call: IEV.functionCall, env: DistributionOperatio
) => ) =>
DistributionOperation.run( DistributionOperation.run(
FromDist( FromDist(
ToScore( #ToScore(
LogScore( LogScore(
DistributionTypes.DistributionOperation.Score_Scalar(answer), DistributionTypes.DistributionOperation.Score_Scalar(answer),
DistributionTypes.DistributionOperation.Score_Dist(prior)->Some, DistributionTypes.DistributionOperation.Score_Dist(prior)->Some,
@ -284,7 +272,7 @@ let dispatchToGenericOutput = (call: IEV.functionCall, env: DistributionOperatio
) => ) =>
DistributionOperation.run( DistributionOperation.run(
FromDist( FromDist(
ToScore(LogScore(DistributionTypes.DistributionOperation.Score_Scalar(answer), None)), #ToScore(LogScore(DistributionTypes.DistributionOperation.Score_Scalar(answer), None)),
prediction, prediction,
), ),
~env, ~env,