diff --git a/packages/squiggle-lang/__tests__/Bandwidth_test.res b/packages/squiggle-lang/__tests__/Bandwidth_test.res index d37e5bb8..4e5c630a 100644 --- a/packages/squiggle-lang/__tests__/Bandwidth_test.res +++ b/packages/squiggle-lang/__tests__/Bandwidth_test.res @@ -4,10 +4,10 @@ open Expect describe("Bandwidth", () => { test("nrd0()", () => { let data = [1., 4., 3., 2.] - expect(Bandwidth.nrd0(data)) -> toEqual(0.7625801874014622) + expect(SampleSetDist_Bandwidth.nrd0(data)) -> toEqual(0.7625801874014622) }) test("nrd()", () => { let data = [1., 4., 3., 2.] - expect(Bandwidth.nrd(data)) -> toEqual(0.8981499984950554) + expect(SampleSetDist_Bandwidth.nrd(data)) -> toEqual(0.8981499984950554) }) }) diff --git a/packages/squiggle-lang/__tests__/Distributions/DistributionOperation_test.res b/packages/squiggle-lang/__tests__/Distributions/DistributionOperation_test.res index cd22d512..34a8dd6e 100644 --- a/packages/squiggle-lang/__tests__/Distributions/DistributionOperation_test.res +++ b/packages/squiggle-lang/__tests__/Distributions/DistributionOperation_test.res @@ -90,14 +90,6 @@ describe("toPointSet", () => { expect(result)->toBeSoCloseTo(5.0, ~digits=0) }) - test("on sample set distribution with under 4 points", () => { - let result = - run(FromDist(ToDist(ToPointSet), SampleSet([0.0, 1.0, 2.0, 3.0])))->outputMap( - FromDist(ToFloat(#Mean)), - ) - expect(result)->toEqual(GenDistError(Other("Converting sampleSet to pointSet failed"))) - }) - test("on sample set", () => { let result = run(FromDist(ToDist(ToPointSet), normalDist5)) diff --git a/packages/squiggle-lang/__tests__/Distributions/Samples_test.res b/packages/squiggle-lang/__tests__/Distributions/SampleSetDist_test.res similarity index 74% rename from packages/squiggle-lang/__tests__/Distributions/Samples_test.res rename to packages/squiggle-lang/__tests__/Distributions/SampleSetDist_test.res index db80f9f7..5a48dd80 100644 --- a/packages/squiggle-lang/__tests__/Distributions/Samples_test.res +++ b/packages/squiggle-lang/__tests__/Distributions/SampleSetDist_test.res @@ -4,12 +4,12 @@ open TestHelpers describe("Continuous and discrete splits", () => { makeTest( "splits (1)", - SampleSet.Internals.T.splitContinuousAndDiscrete([1.432, 1.33455, 2.0]), + SampleSetDist_ToPointSet.Internals.T.splitContinuousAndDiscrete([1.432, 1.33455, 2.0]), ([1.432, 1.33455, 2.0], E.FloatFloatMap.empty()), ) makeTest( "splits (2)", - SampleSet.Internals.T.splitContinuousAndDiscrete([ + SampleSetDist_ToPointSet.Internals.T.splitContinuousAndDiscrete([ 1.432, 1.33455, 2.0, @@ -26,13 +26,13 @@ describe("Continuous and discrete splits", () => { E.A.concatMany([sorted, sorted, sorted, sorted]) |> Belt.SortArray.stableSortBy(_, compare) } - let (_, discrete1) = SampleSet.Internals.T.splitContinuousAndDiscrete( + let (_, discrete1) = SampleSetDist_ToPointSet.Internals.T.splitContinuousAndDiscrete( makeDuplicatedArray(10), ) let toArr1 = discrete1 |> E.FloatFloatMap.toArray makeTest("splitMedium at count=10", toArr1 |> Belt.Array.length, 10) - let (_c, discrete2) = SampleSet.Internals.T.splitContinuousAndDiscrete( + let (_c, discrete2) = SampleSetDist_ToPointSet.Internals.T.splitContinuousAndDiscrete( makeDuplicatedArray(500), ) let toArr2 = discrete2 |> E.FloatFloatMap.toArray diff --git a/packages/squiggle-lang/__tests__/JS__Test.ts b/packages/squiggle-lang/__tests__/JS__Test.ts index ba2f91f4..8e5961a3 100644 --- a/packages/squiggle-lang/__tests__/JS__Test.ts +++ b/packages/squiggle-lang/__tests__/JS__Test.ts @@ -1,4 +1,4 @@ -import { run, GenericDist, resultMap } from "../src/js/index"; +import { run, GenericDist, resultMap, makeSampleSetDist } from "../src/js/index"; let testRun = (x: string) => { let result = run(x); @@ -41,6 +41,7 @@ describe("Multimodal too many weights error", () => { describe("GenericDist", () => { //It's important that sampleCount is less than 9. If it's more, than that will create randomness + //Also, note, the value should be created using makeSampleSetDist() later on. let env = { sampleCount: 8, xyPointLength: 100 }; let dist = new GenericDist( { tag: "SampleSet", value: [3, 4, 5, 6, 6, 7, 10, 15, 30] }, diff --git a/packages/squiggle-lang/src/js/index.ts b/packages/squiggle-lang/src/js/index.ts index 25515db6..4892c2f3 100644 --- a/packages/squiggle-lang/src/js/index.ts +++ b/packages/squiggle-lang/src/js/index.ts @@ -14,6 +14,7 @@ import { resultFloat, resultString, } from "../rescript/TypescriptInterface.gen"; +export {makeSampleSetDist} from "../rescript/TypescriptInterface.gen"; import { Constructors_mean, Constructors_sample, @@ -32,13 +33,13 @@ import { Constructors_algebraicDivide, Constructors_algebraicSubtract, Constructors_algebraicLogarithm, - Constructors_algebraicExponentiate, + Constructors_algebraicPower, Constructors_pointwiseAdd, Constructors_pointwiseMultiply, Constructors_pointwiseDivide, Constructors_pointwiseSubtract, Constructors_pointwiseLogarithm, - Constructors_pointwiseExponentiate, + Constructors_pointwisePower, } from "../rescript/Distributions/DistributionOperation/DistributionOperation.gen"; export let defaultSamplingInputs: SamplingInputs = { @@ -79,6 +80,10 @@ export function resultMap(r: result, mapFn: any): result { } } +export function resultExn(r: result): any { + r.value +} + export class GenericDist { t: genericDist; env: env; @@ -179,9 +184,9 @@ export class GenericDist { ); } - algebraicExponentiate(d2: GenericDist) { + algebraicPower(d2: GenericDist) { return this.mapResultDist( - Constructors_algebraicExponentiate({ env: this.env }, this.t, d2.t) + Constructors_algebraicPower({ env: this.env }, this.t, d2.t) ); } @@ -215,9 +220,9 @@ export class GenericDist { ); } - pointwiseExponentiate(d2: GenericDist) { + pointwisePower(d2: GenericDist) { return this.mapResultDist( - Constructors_pointwiseExponentiate({ env: this.env }, this.t, d2.t) + Constructors_pointwisePower({ env: this.env }, this.t, d2.t) ); } } diff --git a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res index a36674db..71776f61 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res +++ b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res @@ -128,7 +128,10 @@ let rec run = (~env, functionCallInfo: functionCallInfo): outputType => { ->E.R2.fmap(r => Dist(r)) ->OutputLocal.fromResult | ToDist(ToSampleSet(n)) => - dist->GenericDist.sampleN(n)->E.R2.fmap(r => Dist(SampleSet(r)))->OutputLocal.fromResult + dist + ->GenericDist.toSampleSetDist(n) + ->E.R2.fmap(r => Dist(SampleSet(r))) + ->OutputLocal.fromResult | ToDist(ToPointSet) => dist ->GenericDist.toPointSet(~xyPointLength, ~sampleCount, ()) @@ -204,7 +207,8 @@ module Constructors = { C.truncate(dist, leftCutoff, rightCutoff)->run(~env)->toDistR let inspect = (~env, dist) => C.inspect(dist)->run(~env)->toDistR let toString = (~env, dist) => C.toString(dist)->run(~env)->toStringR - let toSparkline = (~env, dist, bucketCount) => C.toSparkline(dist, bucketCount)->run(~env)->toStringR + let toSparkline = (~env, dist, bucketCount) => + C.toSparkline(dist, bucketCount)->run(~env)->toStringR let algebraicAdd = (~env, dist1, dist2) => C.algebraicAdd(dist1, dist2)->run(~env)->toDistR let algebraicMultiply = (~env, dist1, dist2) => C.algebraicMultiply(dist1, dist2)->run(~env)->toDistR @@ -213,8 +217,7 @@ module Constructors = { C.algebraicSubtract(dist1, dist2)->run(~env)->toDistR let algebraicLogarithm = (~env, dist1, dist2) => C.algebraicLogarithm(dist1, dist2)->run(~env)->toDistR - let algebraicExponentiate = (~env, dist1, dist2) => - C.algebraicExponentiate(dist1, dist2)->run(~env)->toDistR + let algebraicPower = (~env, dist1, dist2) => C.algebraicPower(dist1, dist2)->run(~env)->toDistR let pointwiseAdd = (~env, dist1, dist2) => C.pointwiseAdd(dist1, dist2)->run(~env)->toDistR let pointwiseMultiply = (~env, dist1, dist2) => C.pointwiseMultiply(dist1, dist2)->run(~env)->toDistR @@ -223,6 +226,5 @@ module Constructors = { C.pointwiseSubtract(dist1, dist2)->run(~env)->toDistR let pointwiseLogarithm = (~env, dist1, dist2) => C.pointwiseLogarithm(dist1, dist2)->run(~env)->toDistR - let pointwiseExponentiate = (~env, dist1, dist2) => - C.pointwiseExponentiate(dist1, dist2)->run(~env)->toDistR + let pointwisePower = (~env, dist1, dist2) => C.pointwisePower(dist1, dist2)->run(~env)->toDistR } diff --git a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.resi b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.resi index ce0fca72..bfe45013 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.resi +++ b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.resi @@ -79,7 +79,7 @@ module Constructors: { @genType let algebraicLogarithm: (~env: env, genericDist, genericDist) => result @genType - let algebraicExponentiate: (~env: env, genericDist, genericDist) => result + let algebraicPower: (~env: env, genericDist, genericDist) => result @genType let pointwiseAdd: (~env: env, genericDist, genericDist) => result @genType @@ -91,5 +91,5 @@ module Constructors: { @genType let pointwiseLogarithm: (~env: env, genericDist, genericDist) => result @genType - let pointwiseExponentiate: (~env: env, genericDist, genericDist) => result + let pointwisePower: (~env: env, genericDist, genericDist) => result } diff --git a/packages/squiggle-lang/src/rescript/Distributions/DistributionTypes.res b/packages/squiggle-lang/src/rescript/Distributions/DistributionTypes.res index a3e249d3..cab58839 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/DistributionTypes.res +++ b/packages/squiggle-lang/src/rescript/Distributions/DistributionTypes.res @@ -19,7 +19,7 @@ module Operation = { | #Multiply | #Subtract | #Divide - | #Exponentiate + | #Power | #Logarithm ] @@ -28,7 +28,7 @@ module Operation = { | #Add => \"+." | #Multiply => \"*." | #Subtract => \"-." - | #Exponentiate => \"**" + | #Power => \"**" | #Divide => \"/." | #Logarithm => (a, b) => log(a) /. log(b) } diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res index 6bcbb221..b14ea27f 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res @@ -2,17 +2,20 @@ type t = GenericDist_Types.genericDist type error = GenericDist_Types.error type toPointSetFn = t => result -type toSampleSetFn = t => result, error> +type toSampleSetFn = t => result type scaleMultiplyFn = (t, float) => result type pointwiseAddFn = (t, t) => result let sampleN = (t: t, n) => switch t { - | PointSet(r) => Ok(PointSetDist.sampleNRendered(n, r)) - | Symbolic(r) => Ok(SymbolicDist.T.sampleN(n, r)) - | SampleSet(r) => Ok(SampleSet.sampleN(r, n)) + | PointSet(r) => PointSetDist.sampleNRendered(n, r) + | Symbolic(r) => SymbolicDist.T.sampleN(n, r) + | SampleSet(r) => SampleSetDist.sampleN(r, n) } +let toSampleSetDist = (t: t, n) => + SampleSetDist.make(sampleN(t, n))->GenericDist_Types.Error.resultStringToResultError + let fromFloat = (f: float): t => Symbolic(SymbolicDist.Float.make(f)) let toString = (t: t) => @@ -62,22 +65,16 @@ let toPointSet = ( switch (t: t) { | PointSet(pointSet) => Ok(pointSet) | Symbolic(r) => Ok(SymbolicDist.T.toPointSetDist(~xSelection, xyPointLength, r)) - | SampleSet(r) => { - let response = SampleSet.toPointSetDist( - ~samples=r, - ~samplingInputs={ - sampleCount: sampleCount, - outputXYPoints: xyPointLength, - pointSetDistLength: xyPointLength, - kernelWidth: None, - }, - (), - ).pointSetDist - switch response { - | Some(r) => Ok(r) - | None => Error(Other("Converting sampleSet to pointSet failed")) - } - } + | SampleSet(r) => + SampleSetDist.toPointSetDist( + ~samples=r, + ~samplingInputs={ + sampleCount: sampleCount, + outputXYPoints: xyPointLength, + pointSetDistLength: xyPointLength, + kernelWidth: None, + }, + )->GenericDist_Types.Error.resultStringToResultError } } @@ -91,7 +88,7 @@ let toSparkline = (t: t, ~sampleCount: int, ~bucketCount: int=20, unit): result< t ->toPointSet(~xSelection=#Linear, ~xyPointLength=bucketCount * 3, ~sampleCount, ()) ->E.R.bind(r => - r->PointSetDist.toSparkline(bucketCount)->E.R2.errMap(r => Error(GenericDist_Types.Other(r))) + r->PointSetDist.toSparkline(bucketCount)->GenericDist_Types.Error.resultStringToResultError ) module Truncate = { @@ -166,10 +163,12 @@ module AlgebraicCombination = { t1: t, t2: t, ) => { - let arithmeticOperation = Operation.Algebraic.toFn(arithmeticOperation) - E.R.merge(toSampleSet(t1), toSampleSet(t2))->E.R2.fmap(((a, b)) => { - Belt.Array.zip(a, b)->E.A2.fmap(((a, b)) => arithmeticOperation(a, b)) + let fn = Operation.Algebraic.toFn(arithmeticOperation) + E.R.merge(toSampleSet(t1), toSampleSet(t2)) + ->E.R.bind(((t1, t2)) => { + SampleSetDist.map2(~fn, ~t1, ~t2)->GenericDist_Types.Error.resultStringToResultError }) + ->E.R2.fmap(r => GenericDist_Types.SampleSet(r)) } //I'm (Ozzie) really just guessing here, very little idea what's best @@ -200,13 +199,7 @@ module AlgebraicCombination = { | Some(Error(e)) => Error(Other(e)) | None => switch chooseConvolutionOrMonteCarlo(t1, t2) { - | #CalculateWithMonteCarlo => - runMonteCarlo( - toSampleSetFn, - arithmeticOperation, - t1, - t2, - )->E.R2.fmap(r => GenericDist_Types.SampleSet(r)) + | #CalculateWithMonteCarlo => runMonteCarlo(toSampleSetFn, arithmeticOperation, t1, t2) | #CalculateWithConvolution => runConvolution( toPointSetFn, @@ -247,7 +240,7 @@ let pointwiseCombinationFloat = ( ): result => { let m = switch arithmeticOperation { | #Add | #Subtract => Error(GenericDist_Types.DistributionVerticalShiftIsInvalid) - | (#Multiply | #Divide | #Exponentiate | #Logarithm) as arithmeticOperation => + | (#Multiply | #Divide | #Power | #Logarithm) as arithmeticOperation => toPointSetFn(t)->E.R2.fmap(t => { //TODO: Move to PointSet codebase let fn = (secondary, main) => Operation.Scale.toFn(arithmeticOperation, main, secondary) @@ -272,7 +265,7 @@ let mixture = ( ~pointwiseAddFn: pointwiseAddFn, ) => { if E.A.length(values) == 0 { - Error(GenericDist_Types.Other("mixture must have at least 1 element")) + Error(GenericDist_Types.Other("Mixture error: mixture must have at least 1 element")) } else { let totalWeight = values->E.A2.fmap(E.Tuple2.second)->E.A.Floats.sum let properlyWeightedValues = diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi index adf3b9d4..4565ec14 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi @@ -1,11 +1,13 @@ type t = GenericDist_Types.genericDist type error = GenericDist_Types.error type toPointSetFn = t => result -type toSampleSetFn = t => result, error> +type toSampleSetFn = t => result type scaleMultiplyFn = (t, float) => result type pointwiseAddFn = (t, t) => result -let sampleN: (t, int) => result, error> +let sampleN: (t, int) => array + +let toSampleSetDist: (t, int) => Belt.Result.t let fromFloat: float => t 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 b3aeddac..96e7d3f8 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res @@ -1,6 +1,6 @@ type genericDist = | PointSet(PointSetTypes.pointSetDist) - | SampleSet(SampleSet.t) + | SampleSet(SampleSetDist.t) | Symbolic(SymbolicDistTypes.symbolicDist) @genType @@ -10,6 +10,15 @@ type error = | DistributionVerticalShiftIsInvalid | Other(string) +module Error = { + type t = error + + let fromString = (s: string): t => Other(s) + + let resultStringToResultError: result<'a, string> => result<'a, error> = n => + n->E.R2.errMap(r => r->fromString->Error) +} + module Operation = { type direction = | Algebraic @@ -20,7 +29,7 @@ module Operation = { | #Multiply | #Subtract | #Divide - | #Exponentiate + | #Power | #Logarithm ] @@ -29,7 +38,7 @@ module Operation = { | #Add => \"+." | #Multiply => \"*." | #Subtract => \"-." - | #Exponentiate => \"**" + | #Power => \"**" | #Divide => \"/." | #Logarithm => (a, b) => log(a) /. log(b) } @@ -143,8 +152,8 @@ module Constructors = { ToDistCombination(Algebraic, #Logarithm, #Dist(dist2)), dist1, ) - let algebraicExponentiate = (dist1, dist2): t => FromDist( - ToDistCombination(Algebraic, #Exponentiate, #Dist(dist2)), + let algebraicPower = (dist1, dist2): t => FromDist( + ToDistCombination(Algebraic, #Power, #Dist(dist2)), dist1, ) let pointwiseAdd = (dist1, dist2): t => FromDist( @@ -167,8 +176,8 @@ module Constructors = { ToDistCombination(Pointwise, #Logarithm, #Dist(dist2)), dist1, ) - let pointwiseExponentiate = (dist1, dist2): t => FromDist( - ToDistCombination(Pointwise, #Exponentiate, #Dist(dist2)), + let pointwisePower = (dist1, dist2): t => FromDist( + ToDistCombination(Pointwise, #Power, #Dist(dist2)), dist1, ) } diff --git a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/AlgebraicShapeCombination.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/AlgebraicShapeCombination.res index c0d85e60..70440878 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/AlgebraicShapeCombination.res +++ b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/AlgebraicShapeCombination.res @@ -114,7 +114,7 @@ let combineShapesContinuousContinuous = ( | #Subtract => (m1, m2) => m1 -. m2 | #Multiply => (m1, m2) => m1 *. m2 | #Divide => (m1, mInv2) => m1 *. mInv2 - | #Exponentiate => (m1, mInv2) => m1 ** mInv2 + | #Power => (m1, mInv2) => m1 ** mInv2 | #Logarithm => (m1, m2) => log(m1) /. log(m2) } // note: here, mInv2 = mean(1 / t2) ~= 1 / mean(t2) @@ -124,7 +124,7 @@ let combineShapesContinuousContinuous = ( | #Add => (v1, v2, _, _) => v1 +. v2 | #Subtract => (v1, v2, _, _) => v1 +. v2 | #Multiply => (v1, v2, m1, m2) => v1 *. v2 +. v1 *. m2 ** 2. +. v2 *. m1 ** 2. - | #Exponentiate => (v1, v2, m1, m2) => v1 *. v2 +. v1 *. m2 ** 2. +. v2 *. m1 ** 2. + | #Power => (v1, v2, m1, m2) => v1 *. v2 +. v1 *. m2 ** 2. +. v2 *. m1 ** 2. | #Logarithm => (v1, v2, m1, m2) => v1 *. v2 +. v1 *. m2 ** 2. +. v2 *. m1 ** 2. | #Divide => (v1, vInv2, m1, mInv2) => v1 *. vInv2 +. v1 *. mInv2 ** 2. +. vInv2 *. m1 ** 2. } @@ -233,7 +233,7 @@ let combineShapesContinuousDiscrete = ( () } | #Multiply - | #Exponentiate + | #Power | #Logarithm | #Divide => for j in 0 to t2n - 1 { diff --git a/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist.res b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist.res new file mode 100644 index 00000000..fcd4055d --- /dev/null +++ b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist.res @@ -0,0 +1,68 @@ +/* +This is used as a smart constructor. The only way to create a SampleSetDist.t is to call +this constructor. +https://stackoverflow.com/questions/66909578/how-to-make-a-type-constructor-private-in-rescript-except-in-current-module +*/ +module T: { + //This really should be hidden (remove the array). The reason it isn't is to act as an escape hatch in JS__Test.ts. + //When we get a good functional library in TS, we could refactor that out. + @genType + type t = array + let make: array => result + let get: t => array +} = { + type t = array + let make = (a: array) => + if E.A.length(a) > 5 { + Ok(a) + } else { + Error("too small") + } + let get = (a: t) => a +} + +include T + +let length = (t: t) => get(t)->E.A.length + +/* +TODO: Refactor to get a more precise estimate. Also, this code is just fairly messy, could use +some refactoring. +*/ +let toPointSetDist = (~samples: t, ~samplingInputs: SamplingInputs.samplingInputs): result< + PointSetTypes.pointSetDist, + string, +> => + SampleSetDist_ToPointSet.toPointSetDist( + ~samples=get(samples), + ~samplingInputs, + (), + ).pointSetDist->E.O2.toResult("Failed to convert to PointSetDist") + +//Randomly get one sample from the distribution +let sample = (t: t): float => { + let i = E.Int.random(~min=0, ~max=E.A.length(get(t)) - 1) + E.A.unsafe_get(get(t), i) +} + +/* +If asked for a length of samples shorter or equal the length of the distribution, +return this first n samples of this distribution. +Else, return n random samples of the distribution. +The former helps in cases where multiple distributions are correlated. +However, if n > length(t), then there's no clear right answer, so we just randomly +sample everything. +*/ +let sampleN = (t: t, n) => { + if n <= E.A.length(get(t)) { + E.A.slice(get(t), ~offset=0, ~len=n) + } else { + Belt.Array.makeBy(n, _ => sample(t)) + } +} + +//TODO: Figure out what to do if distributions are different lengths. ``zip`` is kind of inelegant for this. +let map2 = (~fn: (float, float) => float, ~t1: t, ~t2: t) => { + let samples = Belt.Array.zip(get(t1), get(t2))->E.A2.fmap(((a, b)) => fn(a, b)) + make(samples) +} diff --git a/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/Bandwidth.res b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist_Bandwidth.res similarity index 94% rename from packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/Bandwidth.res rename to packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist_Bandwidth.res index 6650b862..aef659d1 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/Bandwidth.res +++ b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist_Bandwidth.res @@ -1,4 +1,4 @@ -//The math here was taken from https://github.com/jasondavies/science.js/blob/master/src/stats/bandwidth.js +//The math here was taken from https://github.com/jasondavies/science.js/blob/master/src/stats/SampleSetDist_Bandwidth.js let len = x => E.A.length(x) |> float_of_int diff --git a/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSet.res b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist_ToPointSet.res similarity index 82% rename from packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSet.res rename to packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist_ToPointSet.res index f8bce6f6..59b4fa46 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSet.res +++ b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist_ToPointSet.res @@ -1,8 +1,3 @@ -@genType -type t = array - -// TODO: Refactor to raise correct error when not enough samples - module Internals = { module Types = { type samplingStats = { @@ -75,7 +70,7 @@ module Internals = { let formatUnitWidth = w => Jstat.max([w, 1.0]) |> int_of_float let suggestedUnitWidth = (samples, outputXYPoints) => { - let suggestedXWidth = Bandwidth.nrd0(samples) + let suggestedXWidth = SampleSetDist_Bandwidth.nrd0(samples) xWidthToUnitWidth(samples, outputXYPoints, suggestedXWidth) } @@ -102,7 +97,7 @@ let toPointSetDist = ( let pdf = continuousPart |> E.A.length > 5 ? { - let _suggestedXWidth = Bandwidth.nrd0(continuousPart) + let _suggestedXWidth = SampleSetDist_Bandwidth.nrd0(continuousPart) // todo: This does some recalculating from the last step. let _suggestedUnitWidth = Internals.T.suggestedUnitWidth( continuousPart, @@ -145,25 +140,3 @@ let toPointSetDist = ( samplesParse } - -//Randomly get one sample from the distribution -let sample = (t: t): float => { - let i = E.Int.random(~min=0, ~max=E.A.length(t) - 1) - E.A.unsafe_get(t, i) -} - -/* -If asked for a length of samples shorter or equal the length of the distribution, -return this first n samples of this distribution. -Else, return n random samples of the distribution. -The former helps in cases where multiple distributions are correlated. -However, if n > length(t), then there's no clear right answer, so we just randomly -sample everything. -*/ -let sampleN = (t: t, n) => { - if n <= E.A.length(t) { - E.A.slice(t, ~offset=0, ~len=n) - } else { - Belt.Array.makeBy(n, _ => sample(t)) - } -} diff --git a/packages/squiggle-lang/src/rescript/OldInterpreter/ASTEvaluator.res b/packages/squiggle-lang/src/rescript/OldInterpreter/ASTEvaluator.res index 44c5565e..cd4c241d 100644 --- a/packages/squiggle-lang/src/rescript/OldInterpreter/ASTEvaluator.res +++ b/packages/squiggle-lang/src/rescript/OldInterpreter/ASTEvaluator.res @@ -118,7 +118,7 @@ module PointwiseCombination = { switch pointwiseOp { | #Add => pointwiseAdd(evaluationParams, t1, t2) | #Multiply => pointwiseCombine(\"*.", evaluationParams, t1, t2) - | #Exponentiate => pointwiseCombine(\"**", evaluationParams, t1, t2) + | #Power => pointwiseCombine(\"**", evaluationParams, t1, t2) } } diff --git a/packages/squiggle-lang/src/rescript/OldInterpreter/ASTTypes.res b/packages/squiggle-lang/src/rescript/OldInterpreter/ASTTypes.res index 31217374..17477f8f 100644 --- a/packages/squiggle-lang/src/rescript/OldInterpreter/ASTTypes.res +++ b/packages/squiggle-lang/src/rescript/OldInterpreter/ASTTypes.res @@ -218,15 +218,14 @@ module SamplingDistribution = { algebraicOp, a, b, - ) + ) |> E.O.toResult("Could not get samples") - let pointSetDist = - samples - |> E.O.fmap(r => - SampleSet.toPointSetDist(~samplingInputs=evaluationParams.samplingInputs, ~samples=r, ()) - ) - |> E.O.bind(_, r => r.pointSetDist) - |> E.O.toResult("No response") + let sampleSetDist = samples -> E.R.bind(SampleSetDist.make) + + let pointSetDist = + sampleSetDist + -> E.R.bind(r => + SampleSetDist.toPointSetDist(~samplingInputs=evaluationParams.samplingInputs, ~samples=r)); pointSetDist |> E.R.fmap(r => #Normalize(#RenderedDist(r))) }) } diff --git a/packages/squiggle-lang/src/rescript/OldInterpreter/typeSystem/HardcodedFunctions.res b/packages/squiggle-lang/src/rescript/OldInterpreter/typeSystem/HardcodedFunctions.res index cf8fe470..8302b532 100644 --- a/packages/squiggle-lang/src/rescript/OldInterpreter/typeSystem/HardcodedFunctions.res +++ b/packages/squiggle-lang/src/rescript/OldInterpreter/typeSystem/HardcodedFunctions.res @@ -227,7 +227,7 @@ let all = [ }, (), ), - makeRenderedDistFloat("scaleExp", (dist, float) => verticalScaling(#Exponentiate, dist, float)), + makeRenderedDistFloat("scaleExp", (dist, float) => verticalScaling(#Power, dist, float)), makeRenderedDistFloat("scaleMultiply", (dist, float) => verticalScaling(#Multiply, dist, float)), makeRenderedDistFloat("scaleLog", (dist, float) => verticalScaling(#Logarithm, dist, float)), Multimodal._function, diff --git a/packages/squiggle-lang/src/rescript/OldParser/Parser.res b/packages/squiggle-lang/src/rescript/OldParser/Parser.res index 0a837823..6f5fd9ef 100644 --- a/packages/squiggle-lang/src/rescript/OldParser/Parser.res +++ b/packages/squiggle-lang/src/rescript/OldParser/Parser.res @@ -144,11 +144,11 @@ module MathAdtToDistDst = { | ("subtract", _) => Error("Subtraction needs two operands") | ("multiply", [l, r]) => toOkAlgebraic((#Multiply, l, r)) | ("multiply", _) => Error("Multiplication needs two operands") - | ("pow", [l, r]) => toOkAlgebraic((#Exponentiate, l, r)) + | ("pow", [l, r]) => toOkAlgebraic((#Power, l, r)) | ("pow", _) => Error("Exponentiation needs two operands") | ("dotMultiply", [l, r]) => toOkPointwise((#Multiply, l, r)) | ("dotMultiply", _) => Error("Dotwise multiplication needs two operands") - | ("dotPow", [l, r]) => toOkPointwise((#Exponentiate, l, r)) + | ("dotPow", [l, r]) => toOkPointwise((#Power, l, r)) | ("dotPow", _) => Error("Dotwise exponentiation needs two operands") | ("rightLogShift", [l, r]) => toOkPointwise((#Add, l, r)) | ("rightLogShift", _) => Error("Dotwise addition needs two operands") diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res index 89be2d46..ea65b963 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res @@ -18,8 +18,8 @@ module Helpers = { | "divide" => #Divide | "log" => #Logarithm | "dotDivide" => #Divide - | "pow" => #Exponentiate - | "dotPow" => #Exponentiate + | "pow" => #Power + | "dotPow" => #Power | "multiply" => #Multiply | "dotMultiply" => #Multiply | "dotLog" => #Logarithm diff --git a/packages/squiggle-lang/src/rescript/TypescriptInterface.res b/packages/squiggle-lang/src/rescript/TypescriptInterface.res index fb30ea24..6fe6f3d4 100644 --- a/packages/squiggle-lang/src/rescript/TypescriptInterface.res +++ b/packages/squiggle-lang/src/rescript/TypescriptInterface.res @@ -22,3 +22,6 @@ type resultDist = result type resultFloat = result @genType type resultString = result + +@genType +let makeSampleSetDist = SampleSetDist.make \ No newline at end of file diff --git a/packages/squiggle-lang/src/rescript/Utility/Operation.res b/packages/squiggle-lang/src/rescript/Utility/Operation.res index 55e0b42f..6fb3b24b 100644 --- a/packages/squiggle-lang/src/rescript/Utility/Operation.res +++ b/packages/squiggle-lang/src/rescript/Utility/Operation.res @@ -6,12 +6,12 @@ type algebraicOperation = [ | #Multiply | #Subtract | #Divide - | #Exponentiate + | #Power | #Logarithm ] @genType -type pointwiseOperation = [#Add | #Multiply | #Exponentiate] -type scaleOperation = [#Multiply | #Exponentiate | #Logarithm | #Divide] +type pointwiseOperation = [#Add | #Multiply | #Power] +type scaleOperation = [#Multiply | #Power | #Logarithm | #Divide] type distToFloatOperation = [ | #Pdf(float) | #Cdf(float) @@ -27,7 +27,7 @@ module Algebraic = { | #Add => \"+." | #Subtract => \"-." | #Multiply => \"*." - | #Exponentiate => \"**" + | #Power => \"**" | #Divide => \"/." | #Logarithm => (a, b) => log(a) /. log(b) } @@ -43,7 +43,7 @@ module Algebraic = { | #Add => "+" | #Subtract => "-" | #Multiply => "*" - | #Exponentiate => "**" + | #Power => "**" | #Divide => "/" | #Logarithm => "log" } @@ -56,7 +56,7 @@ module Pointwise = { let toString = x => switch x { | #Add => "+" - | #Exponentiate => "^" + | #Power => "**" | #Multiply => "*" } @@ -83,7 +83,7 @@ module Scale = { switch x { | #Multiply => \"*." | #Divide => \"/." - | #Exponentiate => \"**" + | #Power => \"**" | #Logarithm => (a, b) => log(a) /. log(b) } @@ -91,7 +91,7 @@ module Scale = { switch operation { | #Multiply => j`verticalMultiply($value, $scaleBy) ` | #Divide => j`verticalDivide($value, $scaleBy) ` - | #Exponentiate => j`verticalExponentiate($value, $scaleBy) ` + | #Power => j`verticalPower($value, $scaleBy) ` | #Logarithm => j`verticalLog($value, $scaleBy) ` } @@ -99,7 +99,7 @@ module Scale = { switch x { | #Multiply => (a, b) => Some(a *. b) | #Divide => (a, b) => Some(a /. b) - | #Exponentiate => (_, _) => None + | #Power => (_, _) => None | #Logarithm => (_, _) => None } @@ -107,7 +107,7 @@ module Scale = { switch x { | #Multiply => (_, _) => None // TODO: this could probably just be multiplied out (using Continuous.scaleBy) | #Divide => (_, _) => None - | #Exponentiate => (_, _) => None + | #Power => (_, _) => None | #Logarithm => (_, _) => None } }