First attempt at LogScore
This commit is contained in:
parent
f7afbf9c39
commit
ced3af5813
|
@ -139,6 +139,10 @@ let rec run = (~env, functionCallInfo: functionCallInfo): outputType => {
|
||||||
Dist(dist)
|
Dist(dist)
|
||||||
}
|
}
|
||||||
| ToDist(Normalize) => dist->GenericDist.normalize->Dist
|
| ToDist(Normalize) => dist->GenericDist.normalize->Dist
|
||||||
|
| ToScore(LogScore(t2)) =>
|
||||||
|
GenericDist.logScore(dist, t2, ~toPointSetFn)
|
||||||
|
->E.R2.fmap(r => Float(r))
|
||||||
|
->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, ())
|
||||||
|
@ -227,6 +231,7 @@ module Constructors = {
|
||||||
let pdf = (~env, dist, f) => C.pdf(dist, f)->run(~env)->toFloatR
|
let pdf = (~env, dist, f) => C.pdf(dist, f)->run(~env)->toFloatR
|
||||||
let normalize = (~env, dist) => C.normalize(dist)->run(~env)->toDistR
|
let normalize = (~env, dist) => C.normalize(dist)->run(~env)->toDistR
|
||||||
let isNormalized = (~env, dist) => C.isNormalized(dist)->run(~env)->toBoolR
|
let isNormalized = (~env, dist) => C.isNormalized(dist)->run(~env)->toBoolR
|
||||||
|
let logScore = (~env, dist1, dist2) => C.logScore(dist1, dist2)->run(~env)->toFloatR
|
||||||
let toPointSet = (~env, dist) => C.toPointSet(dist)->run(~env)->toDistR
|
let toPointSet = (~env, dist) => C.toPointSet(dist)->run(~env)->toDistR
|
||||||
let toSampleSet = (~env, dist, n) => C.toSampleSet(dist, n)->run(~env)->toDistR
|
let toSampleSet = (~env, dist, n) => C.toSampleSet(dist, n)->run(~env)->toDistR
|
||||||
let truncate = (~env, dist, leftCutoff, rightCutoff) =>
|
let truncate = (~env, dist, leftCutoff, rightCutoff) =>
|
||||||
|
|
|
@ -57,6 +57,8 @@ module Constructors: {
|
||||||
@genType
|
@genType
|
||||||
let isNormalized: (~env: env, genericDist) => result<bool, error>
|
let isNormalized: (~env: env, genericDist) => result<bool, error>
|
||||||
@genType
|
@genType
|
||||||
|
let logScore: (~env: env, genericDist, genericDist) => result<float, error>
|
||||||
|
@genType
|
||||||
let toPointSet: (~env: env, genericDist) => result<genericDist, error>
|
let toPointSet: (~env: env, genericDist) => result<genericDist, error>
|
||||||
@genType
|
@genType
|
||||||
let toSampleSet: (~env: env, genericDist, int) => result<genericDist, error>
|
let toSampleSet: (~env: env, genericDist, int) => result<genericDist, error>
|
||||||
|
|
|
@ -85,9 +85,12 @@ module DistributionOperation = {
|
||||||
| ToString
|
| ToString
|
||||||
| ToSparkline(int)
|
| ToSparkline(int)
|
||||||
|
|
||||||
|
type toScore = LogScore(genericDist)
|
||||||
|
|
||||||
type fromDist =
|
type fromDist =
|
||||||
| 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)
|
||||||
|
@ -108,6 +111,7 @@ module DistributionOperation = {
|
||||||
| ToFloat(#Mean) => `mean`
|
| ToFloat(#Mean) => `mean`
|
||||||
| ToFloat(#Pdf(r)) => `pdf(${E.Float.toFixed(r)})`
|
| ToFloat(#Pdf(r)) => `pdf(${E.Float.toFixed(r)})`
|
||||||
| ToFloat(#Sample) => `sample`
|
| ToFloat(#Sample) => `sample`
|
||||||
|
| ToScore(LogScore(_)) => `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)})`
|
||||||
|
@ -142,6 +146,7 @@ module Constructors = {
|
||||||
let toSampleSet = (dist, r): t => FromDist(ToDist(ToSampleSet(r)), dist)
|
let toSampleSet = (dist, r): t => FromDist(ToDist(ToSampleSet(r)), dist)
|
||||||
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)
|
||||||
|
let logScore = (dist1, dist2): t => FromDist(ToScore(LogScore(dist2)), dist1)
|
||||||
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(
|
||||||
|
|
|
@ -59,6 +59,13 @@ let integralEndY = (t: t): float =>
|
||||||
|
|
||||||
let isNormalized = (t: t): bool => Js.Math.abs_float(integralEndY(t) -. 1.0) < 1e-7
|
let isNormalized = (t: t): bool => Js.Math.abs_float(integralEndY(t) -. 1.0) < 1e-7
|
||||||
|
|
||||||
|
let logScore = (t1, t2, ~toPointSetFn: toPointSetFn): result<float, error> => {
|
||||||
|
let pointSets = E.R.merge(toPointSetFn(t1), toPointSetFn(t2))
|
||||||
|
pointSets |> E.R2.bind(((a, b)) =>
|
||||||
|
PointSetDist.T.logScore(a, b)->E.R2.errMap(x => DistributionTypes.OperationError(x))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
let toFloatOperation = (
|
let toFloatOperation = (
|
||||||
t,
|
t,
|
||||||
~toPointSetFn: toPointSetFn,
|
~toPointSetFn: toPointSetFn,
|
||||||
|
|
|
@ -23,6 +23,8 @@ let toFloatOperation: (
|
||||||
~distToFloatOperation: Operation.distToFloatOperation,
|
~distToFloatOperation: Operation.distToFloatOperation,
|
||||||
) => result<float, error>
|
) => result<float, error>
|
||||||
|
|
||||||
|
let logScore: (t, t, ~toPointSetFn: toPointSetFn) => result<float, error>
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
let toPointSet: (
|
let toPointSet: (
|
||||||
t,
|
t,
|
||||||
|
|
|
@ -267,6 +267,12 @@ module T = Dist({
|
||||||
}
|
}
|
||||||
let variance = (t: t): float =>
|
let variance = (t: t): float =>
|
||||||
XYShape.Analysis.getVarianceDangerously(t, mean, Analysis.getMeanOfSquares)
|
XYShape.Analysis.getVarianceDangerously(t, mean, Analysis.getMeanOfSquares)
|
||||||
|
|
||||||
|
let logScore = (base: t, reference: t) => {
|
||||||
|
combinePointwise(PointSetDist_Scoring.LogScoring.logScore, base, reference)
|
||||||
|
|> E.R.fmap(shapeMap(XYShape.T.filterYValues(Js.Float.isFinite)))
|
||||||
|
|> E.R.fmap(integralEndY)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
let isNormalized = (t: t): bool => {
|
let isNormalized = (t: t): bool => {
|
||||||
|
|
|
@ -34,6 +34,7 @@ let lastY = (t: t) => t |> getShape |> XYShape.T.lastY
|
||||||
|
|
||||||
let combinePointwise = (
|
let combinePointwise = (
|
||||||
~integralSumCachesFn=(_, _) => None,
|
~integralSumCachesFn=(_, _) => None,
|
||||||
|
~fn=(a, b) => Ok(a +. b),
|
||||||
t1: PointSetTypes.discreteShape,
|
t1: PointSetTypes.discreteShape,
|
||||||
t2: PointSetTypes.discreteShape,
|
t2: PointSetTypes.discreteShape,
|
||||||
): PointSetTypes.discreteShape => {
|
): PointSetTypes.discreteShape => {
|
||||||
|
@ -47,9 +48,8 @@ let combinePointwise = (
|
||||||
// It could be done for pointwise additions, but is that ever needed?
|
// It could be done for pointwise additions, but is that ever needed?
|
||||||
|
|
||||||
make(
|
make(
|
||||||
~integralSumCache=combinedIntegralSum,
|
|
||||||
XYShape.PointwiseCombination.combine(
|
XYShape.PointwiseCombination.combine(
|
||||||
(a, b) => Ok(a +. b),
|
fn,
|
||||||
XYShape.XtoY.discreteInterpolator,
|
XYShape.XtoY.discreteInterpolator,
|
||||||
t1.xyShape,
|
t1.xyShape,
|
||||||
t2.xyShape,
|
t2.xyShape,
|
||||||
|
@ -221,4 +221,10 @@ module T = Dist({
|
||||||
let getMeanOfSquares = t => t |> shapeMap(XYShape.T.square) |> mean
|
let getMeanOfSquares = t => t |> shapeMap(XYShape.T.square) |> mean
|
||||||
XYShape.Analysis.getVarianceDangerously(t, mean, getMeanOfSquares)
|
XYShape.Analysis.getVarianceDangerously(t, mean, getMeanOfSquares)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let logScore = (base: t, reference: t) => {
|
||||||
|
combinePointwise(~fn=PointSetDist_Scoring.LogScoring.logScore, base, reference)
|
||||||
|
|> integralEndY
|
||||||
|
|> (r => Ok(r))
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -33,6 +33,7 @@ module type dist = {
|
||||||
|
|
||||||
let mean: t => float
|
let mean: t => float
|
||||||
let variance: t => float
|
let variance: t => float
|
||||||
|
let logScore: (t,t) => result<float, Operation.Error.t>
|
||||||
}
|
}
|
||||||
|
|
||||||
module Dist = (T: dist) => {
|
module Dist = (T: dist) => {
|
||||||
|
@ -55,6 +56,7 @@ module Dist = (T: dist) => {
|
||||||
let mean = T.mean
|
let mean = T.mean
|
||||||
let variance = T.variance
|
let variance = T.variance
|
||||||
let integralEndY = T.integralEndY
|
let integralEndY = T.integralEndY
|
||||||
|
let logScore = T.logScore
|
||||||
|
|
||||||
let updateIntegralCache = T.updateIntegralCache
|
let updateIntegralCache = T.updateIntegralCache
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,43 @@ let updateIntegralCache = (integralCache, t: t): t => {
|
||||||
integralCache: integralCache,
|
integralCache: integralCache,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let combinePointwise = (
|
||||||
|
~integralSumCachesFn=(_, _) => None,
|
||||||
|
~integralCachesFn=(_, _) => None,
|
||||||
|
fn: (float, float) => result<float, 'e>,
|
||||||
|
t1: t,
|
||||||
|
t2: t,
|
||||||
|
): result<t, 'e> => {
|
||||||
|
let reducedDiscrete =
|
||||||
|
[t1, t2] |> E.A.fmap(toDiscrete) |> E.A.O.concatSomes |> Discrete.reduce(~integralSumCachesFn)
|
||||||
|
|
||||||
|
let reducedContinuous =
|
||||||
|
[t1, t2]
|
||||||
|
|> E.A.fmap(toContinuous)
|
||||||
|
|> E.A.O.concatSomes
|
||||||
|
|> Continuous.reduce(~integralSumCachesFn, fn)
|
||||||
|
|
||||||
|
let combinedIntegralSum = Common.combineIntegralSums(
|
||||||
|
integralSumCachesFn,
|
||||||
|
t1.integralSumCache,
|
||||||
|
t2.integralSumCache,
|
||||||
|
)
|
||||||
|
|
||||||
|
let combinedIntegral = Common.combineIntegrals(
|
||||||
|
integralCachesFn,
|
||||||
|
t1.integralCache,
|
||||||
|
t2.integralCache,
|
||||||
|
)
|
||||||
|
reducedContinuous->E.R2.fmap(continuous =>
|
||||||
|
make(
|
||||||
|
~integralSumCache=combinedIntegralSum,
|
||||||
|
~integralCache=combinedIntegral,
|
||||||
|
~discrete=reducedDiscrete,
|
||||||
|
~continuous,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
module T = Dist({
|
module T = Dist({
|
||||||
type t = PointSetTypes.mixedShape
|
type t = PointSetTypes.mixedShape
|
||||||
type integral = PointSetTypes.continuousShape
|
type integral = PointSetTypes.continuousShape
|
||||||
|
@ -259,6 +296,12 @@ module T = Dist({
|
||||||
| _ => XYShape.Analysis.getVarianceDangerously(t, mean, getMeanOfSquares)
|
| _ => XYShape.Analysis.getVarianceDangerously(t, mean, getMeanOfSquares)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let logScore = (base: t, reference: t) => {
|
||||||
|
combinePointwise(PointSetDist_Scoring.LogScoring.logScore, base, reference) |> E.R.fmap(
|
||||||
|
integralEndY,
|
||||||
|
)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
let combineAlgebraically = (op: Operation.convolutionOperation, t1: t, t2: t): t => {
|
let combineAlgebraically = (op: Operation.convolutionOperation, t1: t, t2: t): t => {
|
||||||
|
@ -307,40 +350,3 @@ let combineAlgebraically = (op: Operation.convolutionOperation, t1: t, t2: t): t
|
||||||
integralCache: None,
|
integralCache: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let combinePointwise = (
|
|
||||||
~integralSumCachesFn=(_, _) => None,
|
|
||||||
~integralCachesFn=(_, _) => None,
|
|
||||||
fn: (float, float) => result<float, 'e>,
|
|
||||||
t1: t,
|
|
||||||
t2: t,
|
|
||||||
): result<t, 'e> => {
|
|
||||||
let reducedDiscrete =
|
|
||||||
[t1, t2] |> E.A.fmap(toDiscrete) |> E.A.O.concatSomes |> Discrete.reduce(~integralSumCachesFn)
|
|
||||||
|
|
||||||
let reducedContinuous =
|
|
||||||
[t1, t2]
|
|
||||||
|> E.A.fmap(toContinuous)
|
|
||||||
|> E.A.O.concatSomes
|
|
||||||
|> Continuous.reduce(~integralSumCachesFn, fn)
|
|
||||||
|
|
||||||
let combinedIntegralSum = Common.combineIntegralSums(
|
|
||||||
integralSumCachesFn,
|
|
||||||
t1.integralSumCache,
|
|
||||||
t2.integralSumCache,
|
|
||||||
)
|
|
||||||
|
|
||||||
let combinedIntegral = Common.combineIntegrals(
|
|
||||||
integralCachesFn,
|
|
||||||
t1.integralCache,
|
|
||||||
t2.integralCache,
|
|
||||||
)
|
|
||||||
reducedContinuous->E.R2.fmap(continuous =>
|
|
||||||
make(
|
|
||||||
~integralSumCache=combinedIntegralSum,
|
|
||||||
~integralCache=combinedIntegral,
|
|
||||||
~discrete=reducedDiscrete,
|
|
||||||
~continuous,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
|
@ -190,6 +190,18 @@ module T = Dist({
|
||||||
| Discrete(m) => Discrete.T.variance(m)
|
| Discrete(m) => Discrete.T.variance(m)
|
||||||
| Continuous(m) => Continuous.T.variance(m)
|
| Continuous(m) => Continuous.T.variance(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let logScore = (t1: t, t2: t) =>
|
||||||
|
switch (t1, t2) {
|
||||||
|
| (Continuous(t1), Continuous(t2)) => Continuous.T.logScore(t1, t2)
|
||||||
|
| (Discrete(t1), Discrete(t2)) => Discrete.T.logScore(t1, t2)
|
||||||
|
| (Mixed(t1), Mixed(t2)) => Mixed.T.logScore(t1, t2)
|
||||||
|
| _ => {
|
||||||
|
let t1 = toMixed(t1)
|
||||||
|
let t2 = toMixed(t2)
|
||||||
|
Mixed.T.logScore(t1, t2)
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
let pdf = (f: float, t: t) => {
|
let pdf = (f: float, t: t) => {
|
||||||
|
@ -239,4 +251,4 @@ let toSparkline = (t: t, bucketCount): result<string, PointSetTypes.sparklineErr
|
||||||
T.toContinuous(t)
|
T.toContinuous(t)
|
||||||
->E.O2.fmap(Continuous.downsampleEquallyOverX(bucketCount))
|
->E.O2.fmap(Continuous.downsampleEquallyOverX(bucketCount))
|
||||||
->E.O2.toResult(PointSetTypes.CannotSparklineDiscrete)
|
->E.O2.toResult(PointSetTypes.CannotSparklineDiscrete)
|
||||||
->E.R2.fmap(r => Continuous.getShape(r).ys->Sparklines.create())
|
->E.R2.fmap(r => Continuous.getShape(r).ys->Sparklines.create())
|
|
@ -0,0 +1,7 @@
|
||||||
|
module LogScoring = {
|
||||||
|
let logFn = Js.Math.log2
|
||||||
|
let subtraction = (a, b) => Ok(a -. b)
|
||||||
|
let logScore = (a: float, b: float): result<float, Operation.Error.t> => Ok(
|
||||||
|
Js.Math.log2(Js.Math.abs_float(a /. b)),
|
||||||
|
)
|
||||||
|
}
|
|
@ -80,6 +80,7 @@ module Helpers = {
|
||||||
dist1,
|
dist1,
|
||||||
)->runGenericOperation
|
)->runGenericOperation
|
||||||
}
|
}
|
||||||
|
|
||||||
let parseNumber = (args: expressionValue): Belt.Result.t<float, string> =>
|
let parseNumber = (args: expressionValue): Belt.Result.t<float, string> =>
|
||||||
switch args {
|
switch args {
|
||||||
| EvNumber(x) => Ok(x)
|
| EvNumber(x) => Ok(x)
|
||||||
|
@ -209,6 +210,9 @@ let dispatchToGenericOutput = (call: ExpressionValue.functionCall): option<
|
||||||
a,
|
a,
|
||||||
)->Some
|
)->Some
|
||||||
| ("normalize", [EvDistribution(dist)]) => Helpers.toDistFn(Normalize, dist)
|
| ("normalize", [EvDistribution(dist)]) => Helpers.toDistFn(Normalize, dist)
|
||||||
|
| ("logScore", [EvDistribution(a), EvDistribution(b)]) => Some(
|
||||||
|
runGenericOperation(FromDist(ToScore(LogScore(b)), a)),
|
||||||
|
)
|
||||||
| ("isNormalized", [EvDistribution(dist)]) => Helpers.toBoolFn(IsNormalized, dist)
|
| ("isNormalized", [EvDistribution(dist)]) => Helpers.toBoolFn(IsNormalized, dist)
|
||||||
| ("toPointSet", [EvDistribution(dist)]) => Helpers.toDistFn(ToPointSet, dist)
|
| ("toPointSet", [EvDistribution(dist)]) => Helpers.toDistFn(ToPointSet, dist)
|
||||||
| ("cdf", [EvDistribution(dist), EvNumber(float)]) => Helpers.toFloatFn(#Cdf(float), dist)
|
| ("cdf", [EvDistribution(dist), EvNumber(float)]) => Helpers.toFloatFn(#Cdf(float), dist)
|
||||||
|
|
|
@ -96,6 +96,7 @@ module T = {
|
||||||
let fromZippedArray = (pairs: array<(float, float)>): t => pairs |> Belt.Array.unzip |> fromArray
|
let fromZippedArray = (pairs: array<(float, float)>): t => pairs |> Belt.Array.unzip |> fromArray
|
||||||
let equallyDividedXs = (t: t, newLength) => E.A.Floats.range(minX(t), maxX(t), newLength)
|
let equallyDividedXs = (t: t, newLength) => E.A.Floats.range(minX(t), maxX(t), newLength)
|
||||||
let toJs = (t: t) => {"xs": t.xs, "ys": t.ys}
|
let toJs = (t: t) => {"xs": t.xs, "ys": t.ys}
|
||||||
|
let filterYValues = (fn, t: t): t => t |> zip |> E.A.filter(((_,y)) => fn(y)) |> fromZippedArray
|
||||||
|
|
||||||
module Validator = {
|
module Validator = {
|
||||||
let fnName = "XYShape validate"
|
let fnName = "XYShape validate"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user