From 0fa954ae634025a20bc3b907d301dc6d98a54829 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Fri, 8 Apr 2022 08:44:04 -0400 Subject: [PATCH] Improves sparklines by integrating them more deeply to the codebase --- .../GenericDist/GenericDistSparkline_Test.res | 16 ++++++++-------- .../DistributionOperation.res | 6 +++++- .../Distributions/GenericDist/GenericDist.res | 18 ++++++++++++------ .../Distributions/GenericDist/GenericDist.resi | 12 +++++------- .../GenericDist/GenericDist_Types.res | 4 ++++ .../PointSetDist/PointSetDist.res | 5 +++++ .../SymbolicDist/SymbolicDist.res | 4 ++-- .../squiggle-lang/src/rescript/Utility/E.res | 6 ++++++ 8 files changed, 47 insertions(+), 24 deletions(-) diff --git a/packages/squiggle-lang/__tests__/GenericDist/GenericDistSparkline_Test.res b/packages/squiggle-lang/__tests__/GenericDist/GenericDistSparkline_Test.res index d2117936..5aa72004 100644 --- a/packages/squiggle-lang/__tests__/GenericDist/GenericDistSparkline_Test.res +++ b/packages/squiggle-lang/__tests__/GenericDist/GenericDistSparkline_Test.res @@ -5,7 +5,7 @@ let {normalDist, uniformDist, betaDist, lognormalDist, cauchyDist, triangularDis let runTest = (name: string, dist : GenericDist_Types.genericDist, expected: string) => { test(name, () => { - let result = GenericDist.toSparkline(~sampleCount=100, ~buckets=20, dist) + let result = GenericDist.toSparkline(dist, ~sampleCount=100, ~buckets=20, ()) switch result { | Ok(sparkline) => expect(sparkline)->toEqual(expected) | Error(err) => expect("Error")->toEqual(expected) @@ -14,11 +14,11 @@ let runTest = (name: string, dist : GenericDist_Types.genericDist, expected: str } describe("sparkline of generic distribution", () => { - runTest("normal", normalDist, `▁▃▄▅▆▇████████▇▆▅▄▃▁`) - runTest("uniform", uniformDist, `▁██▁`) - runTest("beta", betaDist, `▁▅▇█████████▇▇▆▅▄▃▂▁`) - runTest("lognormal", lognormalDist, `▁▇████▇▇▆▆▅▄▄▃▃▂▂▁▁▁`) - runTest("cauchy", cauchyDist, `▁▁▁▂▄▅▆▇████▇▆▅▄▂▁▁▁`) - runTest("triangular", triangularDist, `▁▃▄▅▆▆▇██████▇▆▆▅▄▃▁`) - runTest("exponential", exponentialDist, `███▇▇▆▆▆▅▅▄▄▃▃▃▂▂▁▁▁`) + runTest("normal", normalDist, `▁▁▁▁▁▂▄▆▇██▇▆▄▂▁▁▁▁▁`) + runTest("uniform", uniformDist, `████████████████████`) + runTest("beta", betaDist, `▁▄▇████▇▆▅▄▃▃▂▁▁▁▁▁▁`) + runTest("lognormal", lognormalDist, `▁█▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁`) + runTest("cauchy", cauchyDist, `▁▁▁▁▁▁▁▁▁██▁▁▁▁▁▁▁▁▁`) + runTest("triangular", triangularDist, `▁▁▂▃▄▅▆▇████▇▆▅▄▃▂▁▁`) + runTest("exponential", exponentialDist, `█▅▄▂▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁`) }) diff --git a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res index 351389ae..4b111c97 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res +++ b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res @@ -114,6 +114,10 @@ let rec run = (~env, functionCallInfo: functionCallInfo): outputType => { ->E.R2.fmap(r => Float(r)) ->OutputLocal.fromResult | ToString => dist->GenericDist.toString->String + | ToSparkline(buckets) => + GenericDist.toSparkline(dist, ~sampleCount, ~buckets, ()) + ->E.R2.fmap(r => String(r)) + ->OutputLocal.fromResult | ToDist(Inspect) => { Js.log2("Console log requested: ", dist) Dist(dist) @@ -127,7 +131,7 @@ let rec run = (~env, functionCallInfo: functionCallInfo): outputType => { dist->GenericDist.sampleN(n)->E.R2.fmap(r => Dist(SampleSet(r)))->OutputLocal.fromResult | ToDist(ToPointSet) => dist - ->GenericDist.toPointSet(~xyPointLength, ~sampleCount) + ->GenericDist.toPointSet(~xyPointLength, ~sampleCount, ()) ->E.R2.fmap(r => Dist(PointSet(r))) ->OutputLocal.fromResult | ToDistCombination(Algebraic, _, #Float(_)) => GenDistError(NotYetImplemented) diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res index f3f8402a..58366a77 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res @@ -52,10 +52,16 @@ let toFloatOperation = ( //Todo: If it's a pointSet, but the xyPointLength is different from what it has, it should change. // This is tricky because the case of discrete distributions. // Also, change the outputXYPoints/pointSetDistLength details -let toPointSet = (~xyPointLength, ~sampleCount, t): result => { +let toPointSet = ( + t, + ~xyPointLength, + ~sampleCount, + ~xSelection: GenericDist_Types.Operation.pointsetXSelection=#ByWeight, + unit, +): result => { switch (t: t) { | PointSet(pointSet) => Ok(pointSet) - | Symbolic(r) => Ok(SymbolicDist.T.toPointSetDist(xyPointLength, r)) + | Symbolic(r) => Ok(SymbolicDist.T.toPointSetDist(~xSelection, xyPointLength, r)) | SampleSet(r) => { let response = SampleSet.toPointSetDist( ~samples=r, @@ -75,10 +81,10 @@ let toPointSet = (~xyPointLength, ~sampleCount, t): result => - toPointSet(~xyPointLength=buckets, ~sampleCount, t) - -> E.R.bind(x => x -> PointSetDist.T.toContinuous -> E.O2.toResult(GenericDist_Types.Other("Could not convert to continuous"))) - -> E.R2.fmap(c => Sparklines.create(Continuous.getShape(c).ys, ())) +let toSparkline = (t: t, ~sampleCount: int, ~buckets: int=20, unit): result => + t + ->toPointSet(~xSelection=#Linear, ~xyPointLength=buckets, ~sampleCount, ()) + ->E.R.bind(r => r->PointSetDist.toSparkline->E.R2.errMap(r => Error(GenericDist_Types.Other(r)))) module Truncate = { let trySymbolicSimplification = (leftCutoff, rightCutoff, t: t): option => diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi index c37385e4..5fa24de9 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi @@ -20,22 +20,20 @@ let toFloatOperation: ( ) => result let toPointSet: ( + t, ~xyPointLength: int, ~sampleCount: int, - t, + ~xSelection: GenericDist_Types.Operation.pointsetXSelection=?, + unit, ) => result -let toSparkline: ( - ~sampleCount: int, - ~buckets: int=?, - t, -) => result +let toSparkline: (t, ~sampleCount: int, ~buckets: int=?, unit) => result let truncate: ( t, ~toPointSetFn: toPointSetFn, ~leftCutoff: option=?, ~rightCutoff: option=?, - unit + unit, ) => result let algebraicCombination: ( diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res index 43ce5d74..ec8374b2 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res @@ -41,6 +41,8 @@ module Operation = { | #Sample ] + type pointsetXSelection = [#Linear | #ByWeight] + type toDist = | Normalize | ToPointSet @@ -55,6 +57,7 @@ module Operation = { | ToDist(toDist) | ToDistCombination(direction, arithmeticOperation, [#Dist(genericDist) | #Float(float)]) | ToString + | ToSparkline(int) type singleParamaterFunction = | FromDist(fromDist) @@ -78,6 +81,7 @@ module Operation = { | ToDist(Truncate(_, _)) => `truncate` | ToDist(Inspect) => `inspect` | ToString => `toString` + | ToSparkline(n) => `toSparkline(${E.I.toString(n)})` | ToDistCombination(Algebraic, _, _) => `algebraic` | ToDistCombination(Pointwise, _, _) => `pointwise` } diff --git a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res index 15186e0b..8224f4cb 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res @@ -202,3 +202,8 @@ let operate = (distToFloatOp: Operation.distToFloatOperation, s): float => | #Sample => sample(s) | #Mean => T.mean(s) } + +let toSparkline = (t: t) => + T.toContinuous(t) + ->E.O2.toResult("toContinous Error: Could not convert into continuous distribution") + ->E.R2.fmap(r => Continuous.getShape(r).ys->Sparklines.create()) \ No newline at end of file diff --git a/packages/squiggle-lang/src/rescript/Distributions/SymbolicDist/SymbolicDist.res b/packages/squiggle-lang/src/rescript/Distributions/SymbolicDist/SymbolicDist.res index cd4132b3..3c757d54 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/SymbolicDist/SymbolicDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/SymbolicDist/SymbolicDist.res @@ -346,11 +346,11 @@ module T = { | _ => #NoSolution } - let toPointSetDist = (sampleCount, d: symbolicDist): PointSetTypes.pointSetDist => + let toPointSetDist = (~xSelection=#ByWeight, sampleCount, d: symbolicDist): PointSetTypes.pointSetDist => switch d { | #Float(v) => Discrete(Discrete.make(~integralSumCache=Some(1.0), {xs: [v], ys: [1.0]})) | _ => - let xs = interpolateXs(~xSelection=#ByWeight, d, sampleCount) + let xs = interpolateXs(~xSelection, d, sampleCount) let ys = xs |> E.A.fmap(x => pdf(x, d)) Continuous(Continuous.make(~integralSumCache=Some(1.0), {xs: xs, ys: ys})) } diff --git a/packages/squiggle-lang/src/rescript/Utility/E.res b/packages/squiggle-lang/src/rescript/Utility/E.res index 8e7ec492..01dbde7d 100644 --- a/packages/squiggle-lang/src/rescript/Utility/E.res +++ b/packages/squiggle-lang/src/rescript/Utility/E.res @@ -180,6 +180,12 @@ module R = { module R2 = { let fmap = (a,b) => R.fmap(b,a) let bind = (a, b) => R.bind(b, a) + + //Converts result type to change error type only + let errMap = (a, map) => switch(a){ + | Ok(r) => Ok(r) + | Error(e) => map(e) + } } let safe_fn_of_string = (fn, s: string): option<'a> =>