From 282fa7726b7c5ff906a9fa1062faa7bfb2fcedb9 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Thu, 28 Apr 2022 21:14:03 -0400 Subject: [PATCH 1/2] Added scalePower and scaleLog --- .../DistributionOperation.res | 10 ++++++++++ .../Distributions/DistributionTypes.res | 10 ++++++++++ .../Distributions/GenericDist/GenericDist.res | 1 + .../Distributions/PointSetDist/Continuous.res | 6 ++++-- .../Distributions/PointSetDist/Discrete.res | 17 ++++++++++++----- .../Distributions/PointSetDist/Mixed.res | 9 ++++++--- .../Distributions/PointSetDist/PointSetDist.res | 7 ++++++- .../ReducerInterface_GenericDistribution.res | 9 +++++++++ 8 files changed, 58 insertions(+), 11 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res index 18ee2d6a..91910824 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res +++ b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res @@ -154,6 +154,16 @@ let rec run = (~env, functionCallInfo: functionCallInfo): outputType => { ->GenericDist.toPointSet(~xyPointLength, ~sampleCount, ()) ->E.R2.fmap(r => Dist(PointSet(r))) ->OutputLocal.fromResult + | ToDist(Scale(#Logarithm, f)) => + dist + ->GenericDist.pointwiseCombinationFloat(~toPointSetFn, ~algebraicCombination=#Logarithm, ~f) + ->E.R2.fmap(r => Dist(r)) + ->OutputLocal.fromResult + | ToDist(Scale(#Power, f)) => + dist + ->GenericDist.pointwiseCombinationFloat(~toPointSetFn, ~algebraicCombination=#Power, ~f) + ->E.R2.fmap(r => Dist(r)) + ->OutputLocal.fromResult | ToDistCombination(Algebraic(_), _, #Float(_)) => GenDistError(NotYetImplemented) | ToDistCombination(Algebraic(strategy), arithmeticOperation, #Dist(t2)) => dist diff --git a/packages/squiggle-lang/src/rescript/Distributions/DistributionTypes.res b/packages/squiggle-lang/src/rescript/Distributions/DistributionTypes.res index 93f86798..e970505d 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/DistributionTypes.res +++ b/packages/squiggle-lang/src/rescript/Distributions/DistributionTypes.res @@ -70,10 +70,16 @@ module DistributionOperation = { | #Sample ] + type toScaleFn = [ + | #Power + | #Logarithm + ] + type toDist = | Normalize | ToPointSet | ToSampleSet(int) + | Scale(toScaleFn, float) | Truncate(option, option) | Inspect @@ -113,6 +119,8 @@ module DistributionOperation = { | ToDist(ToSampleSet(r)) => `toSampleSet(${E.I.toString(r)})` | ToDist(Truncate(_, _)) => `truncate` | ToDist(Inspect) => `inspect` + | ToDist(Scale(#Power, r)) => `scalePower(${E.Float.toFixed(r)})` + | ToDist(Scale(#Logarithm, r)) => `scaleLog(${E.Float.toFixed(r)})` | ToString(ToString) => `toString` | ToString(ToSparkline(n)) => `toSparkline(${E.I.toString(n)})` | ToBool(IsNormalized) => `isNormalized` @@ -142,6 +150,8 @@ module Constructors = { let toSampleSet = (dist, r): t => FromDist(ToDist(ToSampleSet(r)), dist) let truncate = (dist, left, right): t => FromDist(ToDist(Truncate(left, right)), dist) let inspect = (dist): t => FromDist(ToDist(Inspect), dist) + let scalePower = (dist, n): t => FromDist(ToDist(Scale(#Power, n)), dist) + let scaleLogarithm = (dist, n): t => FromDist(ToDist(Scale(#Logarithm, n)), dist) let toString = (dist): t => FromDist(ToString(ToString), dist) let toSparkline = (dist, n): t => FromDist(ToString(ToSparkline(n)), dist) let algebraicAdd = (dist1, dist2: genericDist): t => FromDist( diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res index c19bdf7f..25b83bd3 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res @@ -366,6 +366,7 @@ let pointwiseCombination = ( ~algebraicCombination: Operation.algebraicOperation, ~t2: t, ): result => { + Js.log2("PointwiseCombination", algebraicCombination); E.R.merge(toPointSetFn(t1), toPointSetFn(t2))->E.R.bind(((t1, t2)) => PointSetDist.combinePointwise(Operation.Algebraic.toFn(algebraicCombination), t1, t2) ->E.R2.fmap(r => DistributionTypes.PointSet(r)) diff --git a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Continuous.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Continuous.res index d4286387..105b5a05 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Continuous.res +++ b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Continuous.res @@ -156,8 +156,10 @@ let reduce = ( ~integralSumCachesFn: (float, float) => option=(_, _) => None, fn: (float, float) => result, continuousShapes, -): result => - continuousShapes |> E.A.R.foldM(combinePointwise(~integralSumCachesFn, fn), empty) +): result => { + let merge = combinePointwise(~integralSumCachesFn, fn) + continuousShapes |> E.A.R.foldM(merge, empty) +} let mapYResult = ( ~integralSumCacheFn=_ => None, diff --git a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Discrete.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Discrete.res index fdc921c6..1149df7e 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Discrete.res +++ b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Discrete.res @@ -34,9 +34,10 @@ let lastY = (t: t) => t |> getShape |> XYShape.T.lastY let combinePointwise = ( ~integralSumCachesFn=(_, _) => None, + fn, t1: PointSetTypes.discreteShape, t2: PointSetTypes.discreteShape, -): PointSetTypes.discreteShape => { +): result => { let combinedIntegralSum = Common.combineIntegralSums( integralSumCachesFn, t1.integralSumCache, @@ -49,16 +50,22 @@ let combinePointwise = ( make( ~integralSumCache=combinedIntegralSum, XYShape.PointwiseCombination.combine( - (a, b) => Ok(a +. b), + fn, XYShape.XtoY.discreteInterpolator, t1.xyShape, t2.xyShape, )->E.R.toExn("Addition operation should never fail", _), - ) + )->Ok } -let reduce = (~integralSumCachesFn=(_, _) => None, discreteShapes): PointSetTypes.discreteShape => - discreteShapes |> E.A.fold_left(combinePointwise(~integralSumCachesFn), empty) +let reduce = ( + ~integralSumCachesFn=(_, _) => None, + fn: (float, float) => result, + discreteShapes: array, +): result => { + let merge = combinePointwise(~integralSumCachesFn, fn) + discreteShapes |> E.A.R.foldM(merge, empty) +} let updateIntegralSumCache = (integralSumCache, t: t): t => { ...t, diff --git a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Mixed.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Mixed.res index 4ce2bdd6..98e7923a 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Mixed.res +++ b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Mixed.res @@ -316,7 +316,10 @@ let combinePointwise = ( t2: t, ): result => { let reducedDiscrete = - [t1, t2] |> E.A.fmap(toDiscrete) |> E.A.O.concatSomes |> Discrete.reduce(~integralSumCachesFn) + [t1, t2] + |> E.A.fmap(toDiscrete) + |> E.A.O.concatSomes + |> Discrete.reduce(~integralSumCachesFn, fn) let reducedContinuous = [t1, t2] @@ -335,11 +338,11 @@ let combinePointwise = ( t1.integralCache, t2.integralCache, ) - reducedContinuous->E.R2.fmap(continuous => + E.R.merge(reducedContinuous, reducedDiscrete)->E.R2.fmap(((continuous, discrete)) => make( ~integralSumCache=combinedIntegralSum, ~integralCache=combinedIntegral, - ~discrete=reducedDiscrete, + ~discrete, ~continuous, ) ) diff --git a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res index 12aa5477..00c900dc 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res @@ -84,7 +84,12 @@ let combinePointwise = ( m2, )->E.R2.fmap(x => PointSetTypes.Continuous(x)) | (Discrete(m1), Discrete(m2)) => - Ok(PointSetTypes.Discrete(Discrete.combinePointwise(~integralSumCachesFn, m1, m2))) + Discrete.combinePointwise( + ~integralSumCachesFn, + fn, + m1, + m2, + )->E.R2.fmap(x => PointSetTypes.Discrete(x)) | (m1, m2) => Mixed.combinePointwise( ~integralSumCachesFn, diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res index ab76f469..f69ff8b5 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res @@ -211,6 +211,15 @@ let dispatchToGenericOutput = (call: ExpressionValue.functionCall): option< | ("normalize", [EvDistribution(dist)]) => Helpers.toDistFn(Normalize, dist) | ("isNormalized", [EvDistribution(dist)]) => Helpers.toBoolFn(IsNormalized, dist) | ("toPointSet", [EvDistribution(dist)]) => Helpers.toDistFn(ToPointSet, dist) + | ("scaleLog", [EvDistribution(dist)]) => + Helpers.toDistFn(Scale(#Logarithm, MagicNumbers.Math.e), dist) + | ("scaleLog10", [EvDistribution(dist)]) => Helpers.toDistFn(Scale(#Logarithm, 10.0), dist) + | ("scaleLog", [EvDistribution(dist), EvNumber(float)]) => + Helpers.toDistFn(Scale(#Logarithm, float), dist) + | ("scalePow", [EvDistribution(dist), EvNumber(float)]) => + Helpers.toDistFn(Scale(#Power, float), dist) + | ("scaleExp", [EvDistribution(dist)]) => + Helpers.toDistFn(Scale(#Power, MagicNumbers.Math.e), dist) | ("cdf", [EvDistribution(dist), EvNumber(float)]) => Helpers.toFloatFn(#Cdf(float), dist) | ("pdf", [EvDistribution(dist), EvNumber(float)]) => Helpers.toFloatFn(#Pdf(float), dist) | ("inv", [EvDistribution(dist), EvNumber(float)]) => Helpers.toFloatFn(#Inv(float), dist) From 900aeeae29ea6fad0f7efb7594ac4f4445ff633e Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Thu, 28 Apr 2022 21:31:15 -0400 Subject: [PATCH 2/2] Expose integralSum to Squiggle --- .../Distributions/DistributionTypes.res | 1 + .../Distributions/GenericDist/GenericDist.res | 40 ++++++++++--------- .../GenericDist/GenericDist.resi | 2 +- .../ReducerInterface_GenericDistribution.res | 1 + 4 files changed, 25 insertions(+), 19 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/Distributions/DistributionTypes.res b/packages/squiggle-lang/src/rescript/Distributions/DistributionTypes.res index e970505d..255819d1 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/DistributionTypes.res +++ b/packages/squiggle-lang/src/rescript/Distributions/DistributionTypes.res @@ -68,6 +68,7 @@ module DistributionOperation = { | #Pdf(float) | #Mean | #Sample + | #IntegralSum ] type toScaleFn = [ diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res index 25b83bd3..160ce640 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res @@ -62,26 +62,31 @@ let isNormalized = (t: t): bool => Js.Math.abs_float(integralEndY(t) -. 1.0) < 1 let toFloatOperation = ( t, ~toPointSetFn: toPointSetFn, - ~distToFloatOperation: Operation.distToFloatOperation, + ~distToFloatOperation: DistributionTypes.DistributionOperation.toFloat, ) => { - let trySymbolicSolution = switch (t: t) { - | Symbolic(r) => SymbolicDist.T.operate(distToFloatOperation, r)->E.R.toOption - | _ => None - } + switch distToFloatOperation { + | #IntegralSum => Ok(integralEndY(t)) + | (#Pdf(_) | #Cdf(_) | #Inv(_) | #Mean | #Sample) as op => { + let trySymbolicSolution = switch (t: t) { + | Symbolic(r) => SymbolicDist.T.operate(op, r)->E.R.toOption + | _ => None + } - let trySampleSetSolution = switch ((t: t), distToFloatOperation) { - | (SampleSet(sampleSet), #Mean) => SampleSetDist.mean(sampleSet)->Some - | (SampleSet(sampleSet), #Sample) => SampleSetDist.sample(sampleSet)->Some - | (SampleSet(sampleSet), #Inv(r)) => SampleSetDist.percentile(sampleSet, r)->Some - | _ => None - } + let trySampleSetSolution = switch ((t: t), distToFloatOperation) { + | (SampleSet(sampleSet), #Mean) => SampleSetDist.mean(sampleSet)->Some + | (SampleSet(sampleSet), #Sample) => SampleSetDist.sample(sampleSet)->Some + | (SampleSet(sampleSet), #Inv(r)) => SampleSetDist.percentile(sampleSet, r)->Some + | _ => None + } - switch trySymbolicSolution { - | Some(r) => Ok(r) - | None => - switch trySampleSetSolution { - | Some(r) => Ok(r) - | None => toPointSetFn(t)->E.R2.fmap(PointSetDist.operate(distToFloatOperation)) + switch trySymbolicSolution { + | Some(r) => Ok(r) + | None => + switch trySampleSetSolution { + | Some(r) => Ok(r) + | None => toPointSetFn(t)->E.R2.fmap(PointSetDist.operate(op)) + } + } } } } @@ -366,7 +371,6 @@ let pointwiseCombination = ( ~algebraicCombination: Operation.algebraicOperation, ~t2: t, ): result => { - Js.log2("PointwiseCombination", algebraicCombination); E.R.merge(toPointSetFn(t1), toPointSetFn(t2))->E.R.bind(((t1, t2)) => PointSetDist.combinePointwise(Operation.Algebraic.toFn(algebraicCombination), t1, t2) ->E.R2.fmap(r => DistributionTypes.PointSet(r)) diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi index e91803e2..3d143edc 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi @@ -20,7 +20,7 @@ let isNormalized: t => bool let toFloatOperation: ( t, ~toPointSetFn: toPointSetFn, - ~distToFloatOperation: Operation.distToFloatOperation, + ~distToFloatOperation: DistributionTypes.DistributionOperation.toFloat, ) => result @genType diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res index f69ff8b5..a53425e8 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res @@ -196,6 +196,7 @@ let dispatchToGenericOutput = (call: ExpressionValue.functionCall): option< ->SymbolicConstructors.symbolicResultToOutput | ("sample", [EvDistribution(dist)]) => Helpers.toFloatFn(#Sample, dist) | ("mean", [EvDistribution(dist)]) => Helpers.toFloatFn(#Mean, dist) + | ("integralSum", [EvDistribution(dist)]) => Helpers.toFloatFn(#IntegralSum, dist) | ("toString", [EvDistribution(dist)]) => Helpers.toStringFn(ToString, dist) | ("toSparkline", [EvDistribution(dist)]) => Helpers.toStringFn(ToSparkline(20), dist) | ("toSparkline", [EvDistribution(dist), EvNumber(n)]) =>