From a5db33cedf4ec116897bd5c5e429dbc5d112f0ba Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Mon, 4 Apr 2022 11:44:42 -0400 Subject: [PATCH 1/9] Removed unit from DistPlus --- .../src/rescript/GenericDist/GenericDist.resi | 2 +- .../src/rescript/pointSetDist/DistPlus.res | 5 +---- .../src/rescript/pointSetDist/PointSetTypes.res | 11 ----------- 3 files changed, 2 insertions(+), 16 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/GenericDist/GenericDist.resi b/packages/squiggle-lang/src/rescript/GenericDist/GenericDist.resi index f567f6be..46db83a7 100644 --- a/packages/squiggle-lang/src/rescript/GenericDist/GenericDist.resi +++ b/packages/squiggle-lang/src/rescript/GenericDist/GenericDist.resi @@ -30,7 +30,7 @@ let truncate: ( ~toPointSetFn: toPointSetFn, ~leftCutoff: option=?, ~rightCutoff: option=?, - unit, + unit ) => result let algebraicCombination: ( diff --git a/packages/squiggle-lang/src/rescript/pointSetDist/DistPlus.res b/packages/squiggle-lang/src/rescript/pointSetDist/DistPlus.res index 39f355ab..e1ece63d 100644 --- a/packages/squiggle-lang/src/rescript/pointSetDist/DistPlus.res +++ b/packages/squiggle-lang/src/rescript/pointSetDist/DistPlus.res @@ -9,12 +9,11 @@ let make = ~pointSetDist, ~squiggleString, ~domain=Complete, - ~unit=UnspecifiedDistribution, (), ) : t => { let integral = pointSetDistIntegral(pointSetDist); - {pointSetDist, domain, integralCache: integral, unit, squiggleString}; + {pointSetDist, domain, integralCache: integral, squiggleString}; }; let update = @@ -22,14 +21,12 @@ let update = ~pointSetDist=?, ~integralCache=?, ~domain=?, - ~unit=?, ~squiggleString=?, t: t, ) => { pointSetDist: E.O.default(t.pointSetDist, pointSetDist), integralCache: E.O.default(t.integralCache, integralCache), domain: E.O.default(t.domain, domain), - unit: E.O.default(t.unit, unit), squiggleString: E.O.default(t.squiggleString, squiggleString), }; diff --git a/packages/squiggle-lang/src/rescript/pointSetDist/PointSetTypes.res b/packages/squiggle-lang/src/rescript/pointSetDist/PointSetTypes.res index ded9c02d..e2e17a94 100644 --- a/packages/squiggle-lang/src/rescript/pointSetDist/PointSetTypes.res +++ b/packages/squiggle-lang/src/rescript/pointSetDist/PointSetTypes.res @@ -71,25 +71,14 @@ type generationSource = | SquiggleString(string) | Shape(pointSetDist) -type distributionUnit = - | UnspecifiedDistribution - @genType type distPlus = { pointSetDist: pointSetDist, domain: domain, integralCache: continuousShape, - unit: distributionUnit, squiggleString: option, } -module DistributionUnit = { - let toJson = (distributionUnit: distributionUnit) => - switch distributionUnit { - | _ => Js.Null.fromOption(None) - } -} - module Domain = { let excludedProbabilityMass = (t: domain) => switch t { From 51711512fb191f8c323d70edc07b58606b8c038d Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Mon, 4 Apr 2022 11:47:34 -0400 Subject: [PATCH 2/9] Removed Domain from DistPlus --- .../__tests__/DistTypes__Test.res | 89 ------------------- .../src/rescript/pointSetDist/DistPlus.res | 15 +--- .../rescript/pointSetDist/PointSetTypes.res | 39 -------- 3 files changed, 2 insertions(+), 141 deletions(-) delete mode 100644 packages/squiggle-lang/__tests__/DistTypes__Test.res diff --git a/packages/squiggle-lang/__tests__/DistTypes__Test.res b/packages/squiggle-lang/__tests__/DistTypes__Test.res deleted file mode 100644 index fb09d6d9..00000000 --- a/packages/squiggle-lang/__tests__/DistTypes__Test.res +++ /dev/null @@ -1,89 +0,0 @@ -open Jest -open Expect - -let makeTest = (~only=false, str, item1, item2) => - only - ? Only.test(str, () => expect(item1) -> toEqual(item2)) - : test(str, () => expect(item1) -> toEqual(item2)) - -describe("PointSetTypes", () => - describe("Domain", () => { - let makeComplete = (yPoint, expectation) => - makeTest( - "With input: " ++ Js.Float.toString(yPoint), - PointSetTypes.Domain.yPointToSubYPoint(Complete, yPoint), - expectation, - ) - let makeSingle = (direction: [#left | #right], excludingProbabilityMass, yPoint, expectation) => - makeTest( - "Excluding: " ++ - (Js.Float.toString(excludingProbabilityMass) ++ - (" and yPoint: " ++ Js.Float.toString(yPoint))), - PointSetTypes.Domain.yPointToSubYPoint( - direction == #left - ? LeftLimited({xPoint: 3.0, excludingProbabilityMass: excludingProbabilityMass}) - : RightLimited({xPoint: 3.0, excludingProbabilityMass: excludingProbabilityMass}), - yPoint, - ), - expectation, - ) - let makeDouble = (domain, yPoint, expectation) => - makeTest("Excluding: limits", PointSetTypes.Domain.yPointToSubYPoint(domain, yPoint), expectation) - - describe("With Complete Domain", () => { - makeComplete(0.0, Some(0.0)) - makeComplete(0.6, Some(0.6)) - makeComplete(1.0, Some(1.0)) - }) - describe("With Left Limit", () => { - makeSingle(#left, 0.5, 1.0, Some(1.0)) - makeSingle(#left, 0.5, 0.75, Some(0.5)) - makeSingle(#left, 0.8, 0.9, Some(0.5)) - makeSingle(#left, 0.5, 0.4, None) - makeSingle(#left, 0.5, 0.5, Some(0.0)) - }) - describe("With Right Limit", () => { - makeSingle(#right, 0.5, 1.0, None) - makeSingle(#right, 0.5, 0.25, Some(0.5)) - makeSingle(#right, 0.8, 0.5, None) - makeSingle(#right, 0.2, 0.2, Some(0.25)) - makeSingle(#right, 0.5, 0.5, Some(1.0)) - makeSingle(#right, 0.5, 0.0, Some(0.0)) - makeSingle(#right, 0.5, 0.5, Some(1.0)) - }) - describe("With Left and Right Limit", () => { - makeDouble( - LeftAndRightLimited( - {excludingProbabilityMass: 0.25, xPoint: 3.0}, - {excludingProbabilityMass: 0.25, xPoint: 10.0}, - ), - 0.5, - Some(0.5), - ) - makeDouble( - LeftAndRightLimited( - {excludingProbabilityMass: 0.1, xPoint: 3.0}, - {excludingProbabilityMass: 0.1, xPoint: 10.0}, - ), - 0.2, - Some(0.125), - ) - makeDouble( - LeftAndRightLimited( - {excludingProbabilityMass: 0.1, xPoint: 3.0}, - {excludingProbabilityMass: 0.1, xPoint: 10.0}, - ), - 0.1, - Some(0.0), - ) - makeDouble( - LeftAndRightLimited( - {excludingProbabilityMass: 0.1, xPoint: 3.0}, - {excludingProbabilityMass: 0.1, xPoint: 10.0}, - ), - 0.05, - None, - ) - }) - }) -) diff --git a/packages/squiggle-lang/src/rescript/pointSetDist/DistPlus.res b/packages/squiggle-lang/src/rescript/pointSetDist/DistPlus.res index e1ece63d..2b1688b0 100644 --- a/packages/squiggle-lang/src/rescript/pointSetDist/DistPlus.res +++ b/packages/squiggle-lang/src/rescript/pointSetDist/DistPlus.res @@ -8,25 +8,22 @@ let make = ( ~pointSetDist, ~squiggleString, - ~domain=Complete, (), ) : t => { let integral = pointSetDistIntegral(pointSetDist); - {pointSetDist, domain, integralCache: integral, squiggleString}; + {pointSetDist, integralCache: integral, squiggleString}; }; let update = ( ~pointSetDist=?, ~integralCache=?, - ~domain=?, ~squiggleString=?, t: t, ) => { pointSetDist: E.O.default(t.pointSetDist, pointSetDist), integralCache: E.O.default(t.integralCache, integralCache), - domain: E.O.default(t.domain, domain), squiggleString: E.O.default(t.squiggleString, squiggleString), }; @@ -35,12 +32,6 @@ let updateShape = (pointSetDist, t) => { update(~pointSetDist, ~integralCache, t); }; -let domainIncludedProbabilityMass = (t: t) => - Domain.includedProbabilityMass(t.domain); - -let domainIncludedProbabilityMassAdjustment = (t: t, f) => - f *. Domain.includedProbabilityMass(t.domain); - let toPointSetDist = ({pointSetDist, _}: t) => pointSetDist; let pointSetDistFn = (fn, {pointSetDist}: t) => fn(pointSetDist); @@ -70,8 +61,7 @@ module T = let xToY = (f, t: t) => t |> toPointSetDist - |> PointSetDist.T.xToY(f) - |> MixedPoint.fmap(domainIncludedProbabilityMassAdjustment(t)); + |> PointSetDist.T.xToY(f); let minX = pointSetDistFn(PointSetDist.T.minX); let maxX = pointSetDistFn(PointSetDist.T.maxX); @@ -112,7 +102,6 @@ module T = f, toPointSetDist(t), ) - |> domainIncludedProbabilityMassAdjustment(t); }; // TODO: This part is broken when there is a limit, if this is supposed to be taken into account. diff --git a/packages/squiggle-lang/src/rescript/pointSetDist/PointSetTypes.res b/packages/squiggle-lang/src/rescript/pointSetDist/PointSetTypes.res index e2e17a94..15fbd4c3 100644 --- a/packages/squiggle-lang/src/rescript/pointSetDist/PointSetTypes.res +++ b/packages/squiggle-lang/src/rescript/pointSetDist/PointSetTypes.res @@ -74,49 +74,10 @@ type generationSource = @genType type distPlus = { pointSetDist: pointSetDist, - domain: domain, integralCache: continuousShape, squiggleString: option, } -module Domain = { - let excludedProbabilityMass = (t: domain) => - switch t { - | Complete => 0.0 - | LeftLimited({excludingProbabilityMass}) => excludingProbabilityMass - | RightLimited({excludingProbabilityMass}) => excludingProbabilityMass - | LeftAndRightLimited({excludingProbabilityMass: l}, {excludingProbabilityMass: r}) => l +. r - } - - let includedProbabilityMass = (t: domain) => 1.0 -. excludedProbabilityMass(t) - - let initialProbabilityMass = (t: domain) => - switch t { - | Complete - | RightLimited(_) => 0.0 - | LeftLimited({excludingProbabilityMass}) => excludingProbabilityMass - | LeftAndRightLimited({excludingProbabilityMass}, _) => excludingProbabilityMass - } - - let normalizeProbabilityMass = (t: domain) => 1. /. excludedProbabilityMass(t) - - let yPointToSubYPoint = (t: domain, yPoint) => - switch t { - | Complete => Some(yPoint) - | LeftLimited({excludingProbabilityMass}) if yPoint < excludingProbabilityMass => None - | LeftLimited({excludingProbabilityMass}) if yPoint >= excludingProbabilityMass => - Some((yPoint -. excludingProbabilityMass) /. includedProbabilityMass(t)) - | RightLimited({excludingProbabilityMass}) if yPoint > 1. -. excludingProbabilityMass => None - | RightLimited({excludingProbabilityMass}) if yPoint <= 1. -. excludingProbabilityMass => - Some(yPoint /. includedProbabilityMass(t)) - | LeftAndRightLimited({excludingProbabilityMass: l}, _) if yPoint < l => None - | LeftAndRightLimited(_, {excludingProbabilityMass: r}) if yPoint > 1.0 -. r => None - | LeftAndRightLimited({excludingProbabilityMass: l}, _) => - Some((yPoint -. l) /. includedProbabilityMass(t)) - | _ => None - } -} - type mixedPoint = { continuous: float, discrete: float, From 60b760f0cdd007c1d89f7506f203f8fdeb55f64c Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Mon, 4 Apr 2022 11:59:14 -0400 Subject: [PATCH 3/9] Naming refactor of key rescript directories --- .../__tests__/GenericDist/GenericOperation__Test.res | 10 +++++----- .../DistributionOperation/DistributionOperation.res} | 0 .../DistributionOperation/DistributionOperation.resi} | 0 .../{ => Distributions}/GenericDist/GenericDist.res | 0 .../{ => Distributions}/GenericDist/GenericDist.resi | 0 .../GenericDist/GenericDist_Types.res | 0 .../rescript/{ => Distributions}/GenericDist/README.md | 0 .../PointSetDist}/AlgebraicShapeCombination.res | 0 .../PointSetDist}/Continuous.res | 0 .../PointSetDist}/Discrete.res | 0 .../PointSetDist}/Distributions.res | 0 .../PointSetDist}/Mixed.res | 0 .../PointSetDist}/MixedShapeBuilder.res | 0 .../PointSetDist}/PointSetDist.res | 0 .../PointSetDist}/PointSetTypes.res | 0 .../PointSetDist}/XYShape.res | 0 .../SampleSetDist}/Bandwidth.res | 0 .../SampleSetDist}/KdeLibrary.js | 0 .../SampleSetDist}/SampleSet.res | 0 .../SymbolicDist}/SymbolicDist.res | 0 .../SymbolicDist}/SymbolicDistTypes.res | 0 .../src/rescript/{parser => OldParser}/Parser.res | 0 .../ReducerInterface_GenericDistribution.res | 8 ++++---- .../rescript/{interpreter => oldInterpreter}/AST.res | 0 .../{interpreter => oldInterpreter}/ASTEvaluator.res | 0 .../{interpreter => oldInterpreter}/ASTTypes.res | 0 .../{pointSetDist => oldInterpreter}/DistPlus.res | 0 .../typeSystem/HardcodedFunctions.res | 0 .../typeSystem/TypeSystem.res | 0 29 files changed, 9 insertions(+), 9 deletions(-) rename packages/squiggle-lang/src/rescript/{GenericDist/GenericDist_GenericOperation.res => Distributions/DistributionOperation/DistributionOperation.res} (100%) rename packages/squiggle-lang/src/rescript/{GenericDist/GenericDist_GenericOperation.resi => Distributions/DistributionOperation/DistributionOperation.resi} (100%) rename packages/squiggle-lang/src/rescript/{ => Distributions}/GenericDist/GenericDist.res (100%) rename packages/squiggle-lang/src/rescript/{ => Distributions}/GenericDist/GenericDist.resi (100%) rename packages/squiggle-lang/src/rescript/{ => Distributions}/GenericDist/GenericDist_Types.res (100%) rename packages/squiggle-lang/src/rescript/{ => Distributions}/GenericDist/README.md (100%) rename packages/squiggle-lang/src/rescript/{pointSetDist => Distributions/PointSetDist}/AlgebraicShapeCombination.res (100%) rename packages/squiggle-lang/src/rescript/{pointSetDist => Distributions/PointSetDist}/Continuous.res (100%) rename packages/squiggle-lang/src/rescript/{pointSetDist => Distributions/PointSetDist}/Discrete.res (100%) rename packages/squiggle-lang/src/rescript/{pointSetDist => Distributions/PointSetDist}/Distributions.res (100%) rename packages/squiggle-lang/src/rescript/{pointSetDist => Distributions/PointSetDist}/Mixed.res (100%) rename packages/squiggle-lang/src/rescript/{pointSetDist => Distributions/PointSetDist}/MixedShapeBuilder.res (100%) rename packages/squiggle-lang/src/rescript/{pointSetDist => Distributions/PointSetDist}/PointSetDist.res (100%) rename packages/squiggle-lang/src/rescript/{pointSetDist => Distributions/PointSetDist}/PointSetTypes.res (100%) rename packages/squiggle-lang/src/rescript/{pointSetDist => Distributions/PointSetDist}/XYShape.res (100%) rename packages/squiggle-lang/src/rescript/{sampleSet => Distributions/SampleSetDist}/Bandwidth.res (100%) rename packages/squiggle-lang/src/rescript/{sampleSet => Distributions/SampleSetDist}/KdeLibrary.js (100%) rename packages/squiggle-lang/src/rescript/{sampleSet => Distributions/SampleSetDist}/SampleSet.res (100%) rename packages/squiggle-lang/src/rescript/{symbolicDist => Distributions/SymbolicDist}/SymbolicDist.res (100%) rename packages/squiggle-lang/src/rescript/{symbolicDist => Distributions/SymbolicDist}/SymbolicDistTypes.res (100%) rename packages/squiggle-lang/src/rescript/{parser => OldParser}/Parser.res (100%) rename packages/squiggle-lang/src/rescript/{interpreter => oldInterpreter}/AST.res (100%) rename packages/squiggle-lang/src/rescript/{interpreter => oldInterpreter}/ASTEvaluator.res (100%) rename packages/squiggle-lang/src/rescript/{interpreter => oldInterpreter}/ASTTypes.res (100%) rename packages/squiggle-lang/src/rescript/{pointSetDist => oldInterpreter}/DistPlus.res (100%) rename packages/squiggle-lang/src/rescript/{interpreter => oldInterpreter}/typeSystem/HardcodedFunctions.res (100%) rename packages/squiggle-lang/src/rescript/{interpreter => oldInterpreter}/typeSystem/TypeSystem.res (100%) diff --git a/packages/squiggle-lang/__tests__/GenericDist/GenericOperation__Test.res b/packages/squiggle-lang/__tests__/GenericDist/GenericOperation__Test.res index 90d5a67c..aa921892 100644 --- a/packages/squiggle-lang/__tests__/GenericDist/GenericOperation__Test.res +++ b/packages/squiggle-lang/__tests__/GenericDist/GenericOperation__Test.res @@ -1,7 +1,7 @@ open Jest open Expect -let env: GenericDist_GenericOperation.env = { +let env: DistributionOperation.env = { sampleCount: 100, xyPointLength: 100, } @@ -11,9 +11,9 @@ let normalDist10: GenericDist_Types.genericDist = Symbolic(#Normal({mean: 10.0, let normalDist20: GenericDist_Types.genericDist = Symbolic(#Normal({mean: 20.0, stdev: 2.0})) let uniformDist: GenericDist_Types.genericDist = Symbolic(#Uniform({low: 9.0, high: 10.0})) -let {toFloat, toDist, toString, toError} = module(GenericDist_GenericOperation.Output) -let {run} = module(GenericDist_GenericOperation) -let {fmap} = module(GenericDist_GenericOperation.Output) +let {toFloat, toDist, toString, toError} = module(DistributionOperation.Output) +let {run} = module(DistributionOperation) +let {fmap} = module(DistributionOperation.Output) let run = run(~env) let outputMap = fmap(~env) let toExt: option<'a> => 'a = E.O.toExt( @@ -29,7 +29,7 @@ describe("normalize", () => { describe("mean", () => { test("for a normal distribution", () => { - let result = GenericDist_GenericOperation.run(~env, FromDist(ToFloat(#Mean), normalDist)) + let result = DistributionOperation.run(~env, FromDist(ToFloat(#Mean), normalDist)) expect(result)->toEqual(Float(5.0)) }) }) diff --git a/packages/squiggle-lang/src/rescript/GenericDist/GenericDist_GenericOperation.res b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res similarity index 100% rename from packages/squiggle-lang/src/rescript/GenericDist/GenericDist_GenericOperation.res rename to packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.res diff --git a/packages/squiggle-lang/src/rescript/GenericDist/GenericDist_GenericOperation.resi b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.resi similarity index 100% rename from packages/squiggle-lang/src/rescript/GenericDist/GenericDist_GenericOperation.resi rename to packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.resi diff --git a/packages/squiggle-lang/src/rescript/GenericDist/GenericDist.res b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res similarity index 100% rename from packages/squiggle-lang/src/rescript/GenericDist/GenericDist.res rename to packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.res diff --git a/packages/squiggle-lang/src/rescript/GenericDist/GenericDist.resi b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi similarity index 100% rename from packages/squiggle-lang/src/rescript/GenericDist/GenericDist.resi rename to packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist.resi diff --git a/packages/squiggle-lang/src/rescript/GenericDist/GenericDist_Types.res b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res similarity index 100% rename from packages/squiggle-lang/src/rescript/GenericDist/GenericDist_Types.res rename to packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res diff --git a/packages/squiggle-lang/src/rescript/GenericDist/README.md b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/README.md similarity index 100% rename from packages/squiggle-lang/src/rescript/GenericDist/README.md rename to packages/squiggle-lang/src/rescript/Distributions/GenericDist/README.md diff --git a/packages/squiggle-lang/src/rescript/pointSetDist/AlgebraicShapeCombination.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/AlgebraicShapeCombination.res similarity index 100% rename from packages/squiggle-lang/src/rescript/pointSetDist/AlgebraicShapeCombination.res rename to packages/squiggle-lang/src/rescript/Distributions/PointSetDist/AlgebraicShapeCombination.res diff --git a/packages/squiggle-lang/src/rescript/pointSetDist/Continuous.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Continuous.res similarity index 100% rename from packages/squiggle-lang/src/rescript/pointSetDist/Continuous.res rename to packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Continuous.res diff --git a/packages/squiggle-lang/src/rescript/pointSetDist/Discrete.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Discrete.res similarity index 100% rename from packages/squiggle-lang/src/rescript/pointSetDist/Discrete.res rename to packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Discrete.res diff --git a/packages/squiggle-lang/src/rescript/pointSetDist/Distributions.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Distributions.res similarity index 100% rename from packages/squiggle-lang/src/rescript/pointSetDist/Distributions.res rename to packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Distributions.res diff --git a/packages/squiggle-lang/src/rescript/pointSetDist/Mixed.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Mixed.res similarity index 100% rename from packages/squiggle-lang/src/rescript/pointSetDist/Mixed.res rename to packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Mixed.res diff --git a/packages/squiggle-lang/src/rescript/pointSetDist/MixedShapeBuilder.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/MixedShapeBuilder.res similarity index 100% rename from packages/squiggle-lang/src/rescript/pointSetDist/MixedShapeBuilder.res rename to packages/squiggle-lang/src/rescript/Distributions/PointSetDist/MixedShapeBuilder.res diff --git a/packages/squiggle-lang/src/rescript/pointSetDist/PointSetDist.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res similarity index 100% rename from packages/squiggle-lang/src/rescript/pointSetDist/PointSetDist.res rename to packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res diff --git a/packages/squiggle-lang/src/rescript/pointSetDist/PointSetTypes.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetTypes.res similarity index 100% rename from packages/squiggle-lang/src/rescript/pointSetDist/PointSetTypes.res rename to packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetTypes.res diff --git a/packages/squiggle-lang/src/rescript/pointSetDist/XYShape.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/XYShape.res similarity index 100% rename from packages/squiggle-lang/src/rescript/pointSetDist/XYShape.res rename to packages/squiggle-lang/src/rescript/Distributions/PointSetDist/XYShape.res diff --git a/packages/squiggle-lang/src/rescript/sampleSet/Bandwidth.res b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/Bandwidth.res similarity index 100% rename from packages/squiggle-lang/src/rescript/sampleSet/Bandwidth.res rename to packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/Bandwidth.res diff --git a/packages/squiggle-lang/src/rescript/sampleSet/KdeLibrary.js b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/KdeLibrary.js similarity index 100% rename from packages/squiggle-lang/src/rescript/sampleSet/KdeLibrary.js rename to packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/KdeLibrary.js diff --git a/packages/squiggle-lang/src/rescript/sampleSet/SampleSet.res b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSet.res similarity index 100% rename from packages/squiggle-lang/src/rescript/sampleSet/SampleSet.res rename to packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSet.res diff --git a/packages/squiggle-lang/src/rescript/symbolicDist/SymbolicDist.res b/packages/squiggle-lang/src/rescript/Distributions/SymbolicDist/SymbolicDist.res similarity index 100% rename from packages/squiggle-lang/src/rescript/symbolicDist/SymbolicDist.res rename to packages/squiggle-lang/src/rescript/Distributions/SymbolicDist/SymbolicDist.res diff --git a/packages/squiggle-lang/src/rescript/symbolicDist/SymbolicDistTypes.res b/packages/squiggle-lang/src/rescript/Distributions/SymbolicDist/SymbolicDistTypes.res similarity index 100% rename from packages/squiggle-lang/src/rescript/symbolicDist/SymbolicDistTypes.res rename to packages/squiggle-lang/src/rescript/Distributions/SymbolicDist/SymbolicDistTypes.res diff --git a/packages/squiggle-lang/src/rescript/parser/Parser.res b/packages/squiggle-lang/src/rescript/OldParser/Parser.res similarity index 100% rename from packages/squiggle-lang/src/rescript/parser/Parser.res rename to packages/squiggle-lang/src/rescript/OldParser/Parser.res diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res index 8fabdfa8..84e0697f 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res @@ -1,7 +1,7 @@ module ExpressionValue = ReducerInterface_ExpressionValue type expressionValue = ReducerInterface_ExpressionValue.expressionValue -let runGenericOperation = GenericDist_GenericOperation.run( +let runGenericOperation = DistributionOperation.run( ~env={ sampleCount: 1000, xyPointLength: 1000, @@ -86,7 +86,7 @@ module SymbolicConstructors = { let symbolicResultToOutput = ( symbolicResult: result, - ): option => + ): option => switch symbolicResult { | Ok(r) => Some(Dist(Symbolic(r))) | Error(r) => Some(GenDistError(Other(r))) @@ -98,7 +98,7 @@ module Math = { } let dispatchToGenericOutput = (call: ExpressionValue.functionCall): option< - GenericDist_GenericOperation.outputType, + DistributionOperation.outputType, > => { let (fnName, args) = call switch (fnName, args) { @@ -165,7 +165,7 @@ let dispatchToGenericOutput = (call: ExpressionValue.functionCall): option< } } -let genericOutputToReducerValue = (o: GenericDist_GenericOperation.outputType): result< +let genericOutputToReducerValue = (o: DistributionOperation.outputType): result< expressionValue, Reducer_ErrorValue.errorValue, > => diff --git a/packages/squiggle-lang/src/rescript/interpreter/AST.res b/packages/squiggle-lang/src/rescript/oldInterpreter/AST.res similarity index 100% rename from packages/squiggle-lang/src/rescript/interpreter/AST.res rename to packages/squiggle-lang/src/rescript/oldInterpreter/AST.res diff --git a/packages/squiggle-lang/src/rescript/interpreter/ASTEvaluator.res b/packages/squiggle-lang/src/rescript/oldInterpreter/ASTEvaluator.res similarity index 100% rename from packages/squiggle-lang/src/rescript/interpreter/ASTEvaluator.res rename to packages/squiggle-lang/src/rescript/oldInterpreter/ASTEvaluator.res diff --git a/packages/squiggle-lang/src/rescript/interpreter/ASTTypes.res b/packages/squiggle-lang/src/rescript/oldInterpreter/ASTTypes.res similarity index 100% rename from packages/squiggle-lang/src/rescript/interpreter/ASTTypes.res rename to packages/squiggle-lang/src/rescript/oldInterpreter/ASTTypes.res diff --git a/packages/squiggle-lang/src/rescript/pointSetDist/DistPlus.res b/packages/squiggle-lang/src/rescript/oldInterpreter/DistPlus.res similarity index 100% rename from packages/squiggle-lang/src/rescript/pointSetDist/DistPlus.res rename to packages/squiggle-lang/src/rescript/oldInterpreter/DistPlus.res diff --git a/packages/squiggle-lang/src/rescript/interpreter/typeSystem/HardcodedFunctions.res b/packages/squiggle-lang/src/rescript/oldInterpreter/typeSystem/HardcodedFunctions.res similarity index 100% rename from packages/squiggle-lang/src/rescript/interpreter/typeSystem/HardcodedFunctions.res rename to packages/squiggle-lang/src/rescript/oldInterpreter/typeSystem/HardcodedFunctions.res diff --git a/packages/squiggle-lang/src/rescript/interpreter/typeSystem/TypeSystem.res b/packages/squiggle-lang/src/rescript/oldInterpreter/typeSystem/TypeSystem.res similarity index 100% rename from packages/squiggle-lang/src/rescript/interpreter/typeSystem/TypeSystem.res rename to packages/squiggle-lang/src/rescript/oldInterpreter/typeSystem/TypeSystem.res From a2729f34cb103fb17f125e9ad49f9e63eb60228b Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Mon, 4 Apr 2022 13:41:22 -0400 Subject: [PATCH 4/9] Pulled out XYShape to be more separate --- packages/squiggle-lang/src/js/index.ts | 2 +- .../Distributions/DistributionTypes.res | 92 +++++++++++++++++++ .../AlgebraicShapeCombination.res | 3 +- .../Distributions/PointSetDist/Continuous.res | 45 ++++++++- .../Distributions/PointSetDist/Discrete.res | 3 +- .../Distributions/PointSetDist/Mixed.res | 4 +- .../PointSetDist/PointSetTypes.res | 19 +--- .../PointSetDist => utility}/XYShape.res | 61 ++++-------- 8 files changed, 164 insertions(+), 65 deletions(-) create mode 100644 packages/squiggle-lang/src/rescript/Distributions/DistributionTypes.res rename packages/squiggle-lang/src/rescript/{Distributions/PointSetDist => utility}/XYShape.res (90%) diff --git a/packages/squiggle-lang/src/js/index.ts b/packages/squiggle-lang/src/js/index.ts index cee2987d..7856ef6f 100644 --- a/packages/squiggle-lang/src/js/index.ts +++ b/packages/squiggle-lang/src/js/index.ts @@ -1,7 +1,7 @@ import {runAll} from '../rescript/ProgramEvaluator.gen'; import type { Inputs_SamplingInputs_t as SamplingInputs, exportEnv, exportType, exportDistribution} from '../rescript/ProgramEvaluator.gen'; export type { SamplingInputs, exportEnv, exportDistribution } -export type {t as DistPlus} from '../rescript/pointSetDist/DistPlus.gen'; +export type {t as DistPlus} from '../rescript/OldInterpreter/DistPlus.gen'; export let defaultSamplingInputs : SamplingInputs = { sampleCount : 10000, diff --git a/packages/squiggle-lang/src/rescript/Distributions/DistributionTypes.res b/packages/squiggle-lang/src/rescript/Distributions/DistributionTypes.res new file mode 100644 index 00000000..a3e249d3 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/Distributions/DistributionTypes.res @@ -0,0 +1,92 @@ +type genericDist = + | PointSet(PointSetTypes.pointSetDist) + | SampleSet(array) + | Symbolic(SymbolicDistTypes.symbolicDist) + +type error = + | NotYetImplemented + | Unreachable + | DistributionVerticalShiftIsInvalid + | Other(string) + +module Operation = { + type direction = + | Algebraic + | Pointwise + + type arithmeticOperation = [ + | #Add + | #Multiply + | #Subtract + | #Divide + | #Exponentiate + | #Logarithm + ] + + let arithmeticToFn = (arithmetic: arithmeticOperation) => + switch arithmetic { + | #Add => \"+." + | #Multiply => \"*." + | #Subtract => \"-." + | #Exponentiate => \"**" + | #Divide => \"/." + | #Logarithm => (a, b) => log(a) /. log(b) + } + + type toFloat = [ + | #Cdf(float) + | #Inv(float) + | #Pdf(float) + | #Mean + | #Sample + ] +} + +module DistributionOperation = { + type toDist = + | Normalize + | ToPointSet + | ToSampleSet(int) + | Truncate(option, option) + | Inspect + + type toFloatArray = Sample(int) + + type fromDist = + | ToFloat(Operation.toFloat) + | ToDist(toDist) + | ToDistCombination(Operation.direction, Operation.arithmeticOperation, [#Dist(genericDist) | #Float(float)]) + | ToString + + type singleParamaterFunction = + | FromDist(fromDist) + | FromFloat(fromDist) + + type genericFunctionCallInfo = + | FromDist(fromDist, genericDist) + | FromFloat(fromDist, float) + | Mixture(array<(genericDist, float)>) + + let distCallToString = (distFunction: fromDist): string => + switch distFunction { + | ToFloat(#Cdf(r)) => `cdf(${E.Float.toFixed(r)})` + | ToFloat(#Inv(r)) => `inv(${E.Float.toFixed(r)})` + | ToFloat(#Mean) => `mean` + | ToFloat(#Pdf(r)) => `pdf(${E.Float.toFixed(r)})` + | ToFloat(#Sample) => `sample` + | ToDist(Normalize) => `normalize` + | ToDist(ToPointSet) => `toPointSet` + | ToDist(ToSampleSet(r)) => `toSampleSet(${E.I.toString(r)})` + | ToDist(Truncate(_, _)) => `truncate` + | ToDist(Inspect) => `inspect` + | ToString => `toString` + | ToDistCombination(Algebraic, _, _) => `algebraic` + | ToDistCombination(Pointwise, _, _) => `pointwise` + } + + let toString = (d: genericFunctionCallInfo): string => + switch d { + | FromDist(f, _) | FromFloat(f, _) => distCallToString(f) + | Mixture(_) => `mixture` + } +} diff --git a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/AlgebraicShapeCombination.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/AlgebraicShapeCombination.res index 9cfdc66d..d94bd4a5 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/AlgebraicShapeCombination.res +++ b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/AlgebraicShapeCombination.res @@ -118,13 +118,14 @@ let combineShapesContinuousContinuous = ( | #Logarithm => (m1, m2) => log(m1) /. log(m2) } // note: here, mInv2 = mean(1 / t2) ~= 1 / mean(t2) - // TODO: I don't know what the variances are for exponentatiation + // TODO: I don't know what the variances are for exponentatiation or logarithms // converts the variances and means of the two inputs into the variance of the output let combineVariancesFn = switch op { | #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. + | #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. } diff --git a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Continuous.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Continuous.res index 92654b35..f01457b7 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Continuous.res +++ b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Continuous.res @@ -1,6 +1,47 @@ open Distributions type t = PointSetTypes.continuousShape + +module Analysis = { + let integrate = ( + ~indefiniteIntegralStepwise=(p, h1) => h1 *. p, + ~indefiniteIntegralLinear=(p, a, b) => a *. p +. b *. p ** 2.0 /. 2.0, + t: t, + ): float => { + let xs = t.xyShape.xs + let ys = t.xyShape.ys + + E.A.reducei(xs, 0.0, (acc, _x, i) => { + let areaUnderIntegral = // TODO Take this switch statement out of the loop body + switch (t.interpolation, i) { + | (_, 0) => 0.0 + | (#Stepwise, _) => + indefiniteIntegralStepwise(xs[i], ys[i - 1]) -. + indefiniteIntegralStepwise(xs[i - 1], ys[i - 1]) + | (#Linear, _) => + let x1 = xs[i - 1] + let x2 = xs[i] + if x1 == x2 { + 0.0 + } else { + let h1 = ys[i - 1] + let h2 = ys[i] + let b = (h1 -. h2) /. (x1 -. x2) + let a = h1 -. b *. x1 + indefiniteIntegralLinear(x2, a, b) -. indefiniteIntegralLinear(x1, a, b) + } + } + acc +. areaUnderIntegral + }) + } + + let getMeanOfSquares = (t: t) => { + let indefiniteIntegralLinear = (p, a, b) => a *. p ** 3.0 /. 3.0 +. b *. p ** 4.0 /. 4.0 + let indefiniteIntegralStepwise = (p, h1) => h1 *. p ** 3.0 /. 3.0 + integrate(~indefiniteIntegralStepwise, ~indefiniteIntegralLinear, t) + } +} + let getShape = (t: t) => t.xyShape let interpolation = (t: t) => t.interpolation let make = (~interpolation=#Linear, ~integralSumCache=None, ~integralCache=None, xyShape): t => { @@ -194,7 +235,7 @@ module T = Dist({ let indefiniteIntegralStepwise = (p, h1) => h1 *. p ** 2.0 /. 2.0 let indefiniteIntegralLinear = (p, a, b) => a *. p ** 2.0 /. 2.0 +. b *. p ** 3.0 /. 3.0 - XYShape.Analysis.integrateContinuousShape( + Analysis.integrate( ~indefiniteIntegralStepwise, ~indefiniteIntegralLinear, t, @@ -204,7 +245,7 @@ module T = Dist({ XYShape.Analysis.getVarianceDangerously( t, mean, - XYShape.Analysis.getMeanOfSquaresContinuousShape, + Analysis.getMeanOfSquares, ) }) diff --git a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Discrete.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Discrete.res index 3e2cc2ce..3b689453 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Discrete.res +++ b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Discrete.res @@ -209,8 +209,9 @@ module T = Dist({ let s = getShape(t) E.A.reducei(s.xs, 0.0, (acc, x, i) => acc +. x *. s.ys[i]) } + let variance = (t: t): float => { - let getMeanOfSquares = t => t |> shapeMap(XYShape.Analysis.squareXYShape) |> mean + let getMeanOfSquares = t => t |> shapeMap(XYShape.T.square) |> mean XYShape.Analysis.getVarianceDangerously(t, mean, getMeanOfSquares) } }) \ No newline at end of file diff --git a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Mixed.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Mixed.res index cdccdeb2..e05bd408 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Mixed.res +++ b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Mixed.res @@ -213,8 +213,8 @@ module T = Dist({ let getMeanOfSquares = ({discrete, continuous}: t) => { let discreteMean = - discrete |> Discrete.shapeMap(XYShape.Analysis.squareXYShape) |> Discrete.T.mean - let continuousMean = continuous |> XYShape.Analysis.getMeanOfSquaresContinuousShape + discrete |> Discrete.shapeMap(XYShape.T.square) |> Discrete.T.mean + let continuousMean = continuous |> Continuous.Analysis.getMeanOfSquares (discreteMean *. discreteIntegralSum +. continuousMean *. continuousIntegralSum) /. totalIntegralSum } diff --git a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetTypes.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetTypes.res index 15fbd4c3..2d7947c0 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetTypes.res +++ b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetTypes.res @@ -14,21 +14,10 @@ type distributionType = [ | #CDF ] -type xyShape = { - xs: array, - ys: array, -} - -type interpolationStrategy = [ - | #Stepwise - | #Linear -] -type extrapolationStrategy = [ - | #UseZero - | #UseOutermostPoints -] - -type interpolator = (xyShape, int, float) => float +type xyShape = XYShape.xyShape; +type interpolationStrategy = XYShape.interpolationStrategy; +type extrapolationStrategy = XYShape.extrapolationStrategy; +type interpolator = XYShape.extrapolationStrategy; type rec continuousShape = { xyShape: xyShape, diff --git a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/XYShape.res b/packages/squiggle-lang/src/rescript/utility/XYShape.res similarity index 90% rename from packages/squiggle-lang/src/rescript/Distributions/PointSetDist/XYShape.res rename to packages/squiggle-lang/src/rescript/utility/XYShape.res index 6cadec60..ec2df9f8 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/XYShape.res +++ b/packages/squiggle-lang/src/rescript/utility/XYShape.res @@ -1,4 +1,18 @@ -open PointSetTypes +type xyShape = { + xs: array, + ys: array, +} + +type interpolationStrategy = [ + | #Stepwise + | #Linear +] +type extrapolationStrategy = [ + | #UseZero + | #UseOutermostPoints +] + +type interpolator = (xyShape, int, float) => float let interpolate = (xMin: float, xMax: float, yMin: float, yMax: float, xIntended: float): float => { let minProportion = (xMax -. xIntended) /. (xMax -. xMin) @@ -25,6 +39,7 @@ module T = { let xTotalRange = (t: t) => maxX(t) -. minX(t) let mapX = (fn, t: t): t => {xs: E.A.fmap(fn, t.xs), ys: t.ys} let mapY = (fn, t: t): t => {xs: t.xs, ys: E.A.fmap(fn, t.ys)} + let square = mapX(x => x ** 2.0) let zip = ({xs, ys}: t) => Belt.Array.zip(xs, ys) let fromArray = ((xs, ys)): t => {xs: xs, ys: ys} let fromArrays = (xs, ys): t => {xs: xs, ys: ys} @@ -126,8 +141,8 @@ module XtoY = { /* Returns a between-points-interpolating function that can be used with PointwiseCombination.combine. Interpolation can either be stepwise (using the value on the left) or linear. Extrapolation can be `UseZero or `UseOutermostPoints. */ let continuousInterpolator = ( - interpolation: PointSetTypes.interpolationStrategy, - extrapolation: PointSetTypes.extrapolationStrategy, + interpolation: interpolationStrategy, + extrapolation: extrapolationStrategy, ): interpolator => switch (interpolation, extrapolation) { | (#Linear, #UseZero) => @@ -392,49 +407,9 @@ let logScorePoint = (sampleCount, t1, t2) => |> E.O.fmap(Pairs.y) module Analysis = { - let integrateContinuousShape = ( - ~indefiniteIntegralStepwise=(p, h1) => h1 *. p, - ~indefiniteIntegralLinear=(p, a, b) => a *. p +. b *. p ** 2.0 /. 2.0, - t: PointSetTypes.continuousShape, - ): float => { - let xs = t.xyShape.xs - let ys = t.xyShape.ys - - E.A.reducei(xs, 0.0, (acc, _x, i) => { - let areaUnderIntegral = // TODO Take this switch statement out of the loop body - switch (t.interpolation, i) { - | (_, 0) => 0.0 - | (#Stepwise, _) => - indefiniteIntegralStepwise(xs[i], ys[i - 1]) -. - indefiniteIntegralStepwise(xs[i - 1], ys[i - 1]) - | (#Linear, _) => - let x1 = xs[i - 1] - let x2 = xs[i] - if x1 == x2 { - 0.0 - } else { - let h1 = ys[i - 1] - let h2 = ys[i] - let b = (h1 -. h2) /. (x1 -. x2) - let a = h1 -. b *. x1 - indefiniteIntegralLinear(x2, a, b) -. indefiniteIntegralLinear(x1, a, b) - } - } - acc +. areaUnderIntegral - }) - } - - let getMeanOfSquaresContinuousShape = (t: PointSetTypes.continuousShape) => { - let indefiniteIntegralLinear = (p, a, b) => a *. p ** 3.0 /. 3.0 +. b *. p ** 4.0 /. 4.0 - let indefiniteIntegralStepwise = (p, h1) => h1 *. p ** 3.0 /. 3.0 - integrateContinuousShape(~indefiniteIntegralStepwise, ~indefiniteIntegralLinear, t) - } - let getVarianceDangerously = (t: 't, mean: 't => float, getMeanOfSquares: 't => float): float => { let meanSquared = mean(t) ** 2.0 let meanOfSquares = getMeanOfSquares(t) meanOfSquares -. meanSquared } - - let squareXYShape = T.mapX(x => x ** 2.0) } From 6b69a94a1a01fbe53db731a51a4294b924a09585 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Tue, 5 Apr 2022 15:09:47 -0400 Subject: [PATCH 5/9] Added OldInterpreter files --- .../src/rescript/OldInterpreter/AST.res | 24 ++ .../rescript/OldInterpreter/ASTEvaluator.res | 257 ++++++++++++++++++ .../src/rescript/OldInterpreter/ASTTypes.res | 233 ++++++++++++++++ .../src/rescript/OldInterpreter/DistPlus.res | 116 ++++++++ .../typeSystem/HardcodedFunctions.res | 234 ++++++++++++++++ .../OldInterpreter/typeSystem/TypeSystem.res | 204 ++++++++++++++ 6 files changed, 1068 insertions(+) create mode 100644 packages/squiggle-lang/src/rescript/OldInterpreter/AST.res create mode 100644 packages/squiggle-lang/src/rescript/OldInterpreter/ASTEvaluator.res create mode 100644 packages/squiggle-lang/src/rescript/OldInterpreter/ASTTypes.res create mode 100644 packages/squiggle-lang/src/rescript/OldInterpreter/DistPlus.res create mode 100644 packages/squiggle-lang/src/rescript/OldInterpreter/typeSystem/HardcodedFunctions.res create mode 100644 packages/squiggle-lang/src/rescript/OldInterpreter/typeSystem/TypeSystem.res diff --git a/packages/squiggle-lang/src/rescript/OldInterpreter/AST.res b/packages/squiggle-lang/src/rescript/OldInterpreter/AST.res new file mode 100644 index 00000000..2dca6ffc --- /dev/null +++ b/packages/squiggle-lang/src/rescript/OldInterpreter/AST.res @@ -0,0 +1,24 @@ +open ASTTypes + +let toString = ASTTypes.Node.toString + +let envs = (samplingInputs, environment) => { + samplingInputs: samplingInputs, + environment: environment, + evaluateNode: ASTEvaluator.toLeaf, +} + +let toLeaf = (samplingInputs, environment, node: node) => + ASTEvaluator.toLeaf(envs(samplingInputs, environment), node) + +let toPointSetDist = (samplingInputs, environment, node: node) => + switch toLeaf(samplingInputs, environment, node) { + | Ok(#RenderedDist(pointSetDist)) => Ok(pointSetDist) + | Ok(_) => Error("Rendering failed.") + | Error(e) => Error(e) + } + +let runFunction = (samplingInputs, environment, inputs, fn: ASTTypes.Function.t) => { + let params = envs(samplingInputs, environment) + ASTTypes.Function.run(params, inputs, fn) +} \ No newline at end of file diff --git a/packages/squiggle-lang/src/rescript/OldInterpreter/ASTEvaluator.res b/packages/squiggle-lang/src/rescript/OldInterpreter/ASTEvaluator.res new file mode 100644 index 00000000..44c5565e --- /dev/null +++ b/packages/squiggle-lang/src/rescript/OldInterpreter/ASTEvaluator.res @@ -0,0 +1,257 @@ +open ASTTypes + +type tResult = node => result + +/* Given two random variables A and B, this returns the distribution + of a new variable that is the result of the operation on A and B. + For instance, normal(0, 1) + normal(1, 1) -> normal(1, 2). + In general, this is implemented via convolution. */ +module AlgebraicCombination = { + let tryAnalyticalSimplification = (operation, t1: node, t2: node) => + switch (operation, t1, t2) { + | (operation, #SymbolicDist(d1), #SymbolicDist(d2)) => + switch SymbolicDist.T.tryAnalyticalSimplification(d1, d2, operation) { + | #AnalyticalSolution(symbolicDist) => Ok(#SymbolicDist(symbolicDist)) + | #Error(er) => Error(er) + | #NoSolution => Ok(#AlgebraicCombination(operation, t1, t2)) + } + | _ => Ok(#AlgebraicCombination(operation, t1, t2)) + } + + let combinationByRendering = (evaluationParams, algebraicOp, t1: node, t2: node): result< + node, + string, + > => + E.R.merge( + Node.ensureIsRenderedAndGetShape(evaluationParams, t1), + Node.ensureIsRenderedAndGetShape(evaluationParams, t2), + ) |> E.R.fmap(((a, b)) => #RenderedDist(PointSetDist.combineAlgebraically(algebraicOp, a, b))) + + let nodeScore: node => int = x => + switch x { + | #SymbolicDist(#Float(_)) => 1 + | #SymbolicDist(_) => 1000 + | #RenderedDist(Discrete(m)) => m.xyShape |> XYShape.T.length + | #RenderedDist(Mixed(_)) => 1000 + | #RenderedDist(Continuous(_)) => 1000 + | _ => 1000 + } + + let choose = (t1: node, t2: node) => + nodeScore(t1) * nodeScore(t2) > 10000 ? #Sampling : #Analytical + + let combine = (evaluationParams, algebraicOp, t1: node, t2: node): result => + E.R.merge( + ASTTypes.SamplingDistribution.renderIfIsNotSamplingDistribution(evaluationParams, t1), + ASTTypes.SamplingDistribution.renderIfIsNotSamplingDistribution(evaluationParams, t2), + ) |> E.R.bind(_, ((a, b)) => + switch choose(a, b) { + | #Sampling => + ASTTypes.SamplingDistribution.combineShapesUsingSampling( + evaluationParams, + algebraicOp, + a, + b, + ) + | #Analytical => combinationByRendering(evaluationParams, algebraicOp, a, b) + } + ) + + let operationToLeaf = ( + evaluationParams: evaluationParams, + algebraicOp: Operation.algebraicOperation, + t1: node, + t2: node, + ): result => + algebraicOp + |> tryAnalyticalSimplification(_, t1, t2) + |> E.R.bind(_, x => + switch x { + | #SymbolicDist(_) as t => Ok(t) + | _ => combine(evaluationParams, algebraicOp, t1, t2) + } + ) +} + +module PointwiseCombination = { + //TODO: This is crude and slow. It forces everything to be pointSetDist, even though much + //of the process could happen on symbolic distributions without a conversion to be a pointSetDist. + let pointwiseAdd = (evaluationParams: evaluationParams, t1: node, t2: node) => + switch (Node.render(evaluationParams, t1), Node.render(evaluationParams, t2)) { + | (Ok(#RenderedDist(rs1)), Ok(#RenderedDist(rs2))) => + Ok( + #RenderedDist( + PointSetDist.combinePointwise( + ~integralSumCachesFn=(a, b) => Some(a +. b), + ~integralCachesFn=(a, b) => Some( + Continuous.combinePointwise(~distributionType=#CDF, \"+.", a, b), + ), + \"+.", + rs1, + rs2, + ), + ), + ) + | (Error(e1), _) => Error(e1) + | (_, Error(e2)) => Error(e2) + | _ => Error("Pointwise combination: rendering failed.") + } + + let pointwiseCombine = (fn, evaluationParams: evaluationParams, t1: node, t2: node) => + switch // TODO: construct a function that we can easily sample from, to construct + // a RenderedDist. Use the xMin and xMax of the rendered pointSetDists to tell the sampling function where to look. + // TODO: This should work for symbolic distributions too! + (Node.render(evaluationParams, t1), Node.render(evaluationParams, t2)) { + | (Ok(#RenderedDist(rs1)), Ok(#RenderedDist(rs2))) => + Ok(#RenderedDist(PointSetDist.combinePointwise(fn, rs1, rs2))) + | (Error(e1), _) => Error(e1) + | (_, Error(e2)) => Error(e2) + | _ => Error("Pointwise combination: rendering failed.") + } + + let operationToLeaf = ( + evaluationParams: evaluationParams, + pointwiseOp: Operation.pointwiseOperation, + t1: node, + t2: node, + ) => + switch pointwiseOp { + | #Add => pointwiseAdd(evaluationParams, t1, t2) + | #Multiply => pointwiseCombine(\"*.", evaluationParams, t1, t2) + | #Exponentiate => pointwiseCombine(\"**", evaluationParams, t1, t2) + } +} + +module Truncate = { + type simplificationResult = [ + | #Solution(ASTTypes.node) + | #Error(string) + | #NoSolution + ] + + let trySimplification = (leftCutoff, rightCutoff, t): simplificationResult => + switch (leftCutoff, rightCutoff, t) { + | (None, None, t) => #Solution(t) + | (Some(lc), Some(rc), _) if lc > rc => + #Error("Left truncation bound must be smaller than right truncation bound.") + | (lc, rc, #SymbolicDist(#Uniform(u))) => + #Solution(#SymbolicDist(#Uniform(SymbolicDist.Uniform.truncate(lc, rc, u)))) + | _ => #NoSolution + } + + let truncateAsShape = (evaluationParams: evaluationParams, leftCutoff, rightCutoff, t) => + switch // TODO: use named args for xMin/xMax in renderToShape; if we're lucky we can at least get the tail + // of a distribution we otherwise wouldn't get at all + Node.ensureIsRendered(evaluationParams, t) { + | Ok(#RenderedDist(rs)) => + Ok(#RenderedDist(PointSetDist.T.truncate(leftCutoff, rightCutoff, rs))) + | Error(e) => Error(e) + | _ => Error("Could not truncate distribution.") + } + + let operationToLeaf = ( + evaluationParams, + leftCutoff: option, + rightCutoff: option, + t: node, + ): result => + t + |> trySimplification(leftCutoff, rightCutoff) + |> ( + x => + switch x { + | #Solution(t) => Ok(t) + | #Error(e) => Error(e) + | #NoSolution => truncateAsShape(evaluationParams, leftCutoff, rightCutoff, t) + } + ) +} + +module Normalize = { + let rec operationToLeaf = (evaluationParams, t: node): result => + switch t { + | #RenderedDist(s) => Ok(#RenderedDist(PointSetDist.T.normalize(s))) + | #SymbolicDist(_) => Ok(t) + | _ => ASTTypes.Node.evaluateAndRetry(evaluationParams, operationToLeaf, t) + } +} + +module FunctionCall = { + let _runHardcodedFunction = (name, evaluationParams, args) => + TypeSystem.Function.Ts.findByNameAndRun(HardcodedFunctions.all, name, evaluationParams, args) + + let _runLocalFunction = (name, evaluationParams: evaluationParams, args) => + Environment.getFunction(evaluationParams.environment, name) |> E.R.bind(_, ((argNames, fn)) => + ASTTypes.Function.run(evaluationParams, args, (argNames, fn)) + ) + + let _runWithEvaluatedInputs = ( + evaluationParams: ASTTypes.evaluationParams, + name, + args: array, + ) => + _runHardcodedFunction(name, evaluationParams, args) |> E.O.default( + _runLocalFunction(name, evaluationParams, args), + ) + + // TODO: This forces things to be floats + let run = (evaluationParams, name, args) => + args + |> E.A.fmap(a => evaluationParams.evaluateNode(evaluationParams, a)) + |> E.A.R.firstErrorOrOpen + |> E.R.bind(_, _runWithEvaluatedInputs(evaluationParams, name)) +} + +module Render = { + let rec operationToLeaf = (evaluationParams: evaluationParams, t: node): result => + switch t { + | #Function(_) => Error("Cannot render a function") + | #SymbolicDist(d) => + Ok( + #RenderedDist( + SymbolicDist.T.toPointSetDist(evaluationParams.samplingInputs.pointSetDistLength, d), + ), + ) + | #RenderedDist(_) as t => Ok(t) // already a rendered pointSetDist, we're done here + | _ => ASTTypes.Node.evaluateAndRetry(evaluationParams, operationToLeaf, t) + } +} + +/* This function recursively goes through the nodes of the parse tree, + replacing each Operation node and its subtree with a Data node. + Whenever possible, the replacement produces a new Symbolic Data node, + but most often it will produce a RenderedDist. + This function is used mainly to turn a parse tree into a single RenderedDist + that can then be displayed to the user. */ +let rec toLeaf = (evaluationParams: ASTTypes.evaluationParams, node: node): result => + switch node { + // Leaf nodes just stay leaf nodes + | #SymbolicDist(_) + | #Function(_) + | #RenderedDist(_) => + Ok(node) + | #Array(args) => + args |> E.A.fmap(toLeaf(evaluationParams)) |> E.A.R.firstErrorOrOpen |> E.R.fmap(r => #Array(r)) + // Operations nevaluationParamsd to be turned into leaves + | #AlgebraicCombination(algebraicOp, t1, t2) => + AlgebraicCombination.operationToLeaf(evaluationParams, algebraicOp, t1, t2) + | #PointwiseCombination(pointwiseOp, t1, t2) => + PointwiseCombination.operationToLeaf(evaluationParams, pointwiseOp, t1, t2) + | #Truncate(leftCutoff, rightCutoff, t) => + Truncate.operationToLeaf(evaluationParams, leftCutoff, rightCutoff, t) + | #Normalize(t) => Normalize.operationToLeaf(evaluationParams, t) + | #Render(t) => Render.operationToLeaf(evaluationParams, t) + | #Hash(t) => + t + |> E.A.fmap(((name: string, node: node)) => + toLeaf(evaluationParams, node) |> E.R.fmap(r => (name, r)) + ) + |> E.A.R.firstErrorOrOpen + |> E.R.fmap(r => #Hash(r)) + | #Symbol(r) => + ASTTypes.Environment.get(evaluationParams.environment, r) + |> E.O.toResult("Undeclared variable " ++ r) + |> E.R.bind(_, toLeaf(evaluationParams)) + | #FunctionCall(name, args) => + FunctionCall.run(evaluationParams, name, args) |> E.R.bind(_, toLeaf(evaluationParams)) + } diff --git a/packages/squiggle-lang/src/rescript/OldInterpreter/ASTTypes.res b/packages/squiggle-lang/src/rescript/OldInterpreter/ASTTypes.res new file mode 100644 index 00000000..31217374 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/OldInterpreter/ASTTypes.res @@ -0,0 +1,233 @@ +@genType +type rec hash = array<(string, node)> +and node = [ + | #SymbolicDist(SymbolicDistTypes.symbolicDist) + | #RenderedDist(PointSetTypes.pointSetDist) + | #Symbol(string) + | #Hash(hash) + | #Array(array) + | #Function(array, node) + | #AlgebraicCombination(Operation.algebraicOperation, node, node) + | #PointwiseCombination(Operation.pointwiseOperation, node, node) + | #Normalize(node) + | #Render(node) + | #Truncate(option, option, node) + | #FunctionCall(string, array) +] + +type statement = [ + | #Assignment(string, node) + | #Expression(node) +] +type program = array + +type environment = Belt.Map.String.t + +type rec evaluationParams = { + samplingInputs: SamplingInputs.samplingInputs, + environment: environment, + evaluateNode: (evaluationParams, node) => Belt.Result.t, +} + +module Environment = { + type t = environment + module MS = Belt.Map.String + let fromArray = MS.fromArray + let empty: t = []->fromArray + let mergeKeepSecond = (a: t, b: t) => + MS.merge(a, b, (_, a, b) => + switch (a, b) { + | (_, Some(b)) => Some(b) + | (Some(a), _) => Some(a) + | _ => None + } + ) + let update = (t, str, fn) => MS.update(t, str, fn) + let get = (t: t, str) => MS.get(t, str) + let getFunction = (t: t, str) => + switch get(t, str) { + | Some(#Function(argNames, fn)) => Ok((argNames, fn)) + | _ => Error("Function " ++ (str ++ " not found")) + } +} + +module Node = { + let getFloat = (node: node) => + node |> ( + x => + switch x { + | #RenderedDist(Discrete({xyShape: {xs: [x], ys: [1.0]}})) => Some(x) + | #SymbolicDist(#Float(x)) => Some(x) + | _ => None + } + ) + + let evaluate = (evaluationParams: evaluationParams) => + evaluationParams.evaluateNode(evaluationParams) + + let evaluateAndRetry = (evaluationParams, fn, node) => + node |> evaluationParams.evaluateNode(evaluationParams) |> E.R.bind(_, fn(evaluationParams)) + + let rec toString: node => string = x => + switch x { + | #SymbolicDist(d) => SymbolicDist.T.toString(d) + | #RenderedDist(_) => "[renderedShape]" + | #AlgebraicCombination(op, t1, t2) => + Operation.Algebraic.format(op, toString(t1), toString(t2)) + | #PointwiseCombination(op, t1, t2) => + Operation.Pointwise.format(op, toString(t1), toString(t2)) + | #Normalize(t) => "normalize(k" ++ (toString(t) ++ ")") + | #Truncate(lc, rc, t) => Operation.Truncate.toString(lc, rc, toString(t)) + | #Render(t) => toString(t) + | #Symbol(t) => "Symbol: " ++ t + | #FunctionCall(name, args) => + "[Function call: (" ++ + (name ++ + ((args |> E.A.fmap(toString) |> Js.String.concatMany(_, ",")) ++ ")]")) + | #Function(args, internal) => + "[Function: (" ++ ((args |> Js.String.concatMany(_, ",")) ++ (toString(internal) ++ ")]")) + | #Array(a) => "[" ++ ((a |> E.A.fmap(toString) |> Js.String.concatMany(_, ",")) ++ "]") + | #Hash(h) => + "{" ++ + ((h + |> E.A.fmap(((name, value)) => name ++ (":" ++ toString(value))) + |> Js.String.concatMany(_, ",")) ++ + "}") + } + + let render = (evaluationParams: evaluationParams, r) => #Render(r) |> evaluate(evaluationParams) + + let ensureIsRendered = (params, t) => + switch t { + | #RenderedDist(_) => Ok(t) + | _ => + switch render(params, t) { + | Ok(#RenderedDist(r)) => Ok(#RenderedDist(r)) + | Ok(_) => Error("Did not render as requested") + | Error(e) => Error(e) + } + } + + let ensureIsRenderedAndGetShape = (params, t) => + switch ensureIsRendered(params, t) { + | Ok(#RenderedDist(r)) => Ok(r) + | Ok(_) => Error("Did not render as requested") + | Error(e) => Error(e) + } + + let toPointSetDist = (item: node) => + switch item { + | #RenderedDist(r) => Some(r) + | _ => None + } + + let _toFloat = (t: PointSetTypes.pointSetDist) => + switch t { + | Discrete({xyShape: {xs: [x], ys: [1.0]}}) => Some(#SymbolicDist(#Float(x))) + | _ => None + } + + let toFloat = (item: node): result => + item |> toPointSetDist |> E.O.bind(_, _toFloat) |> E.O.toResult("Not valid shape") +} + +module Function = { + type t = (array, node) + let fromNode: node => option = node => + switch node { + | #Function(r) => Some(r) + | _ => None + } + let argumentNames = ((a, _): t) => a + let internals = ((_, b): t) => b + let run = (evaluationParams: evaluationParams, args: array, t: t) => + if E.A.length(args) == E.A.length(argumentNames(t)) { + let newEnvironment = Belt.Array.zip(argumentNames(t), args) |> Environment.fromArray + let newEvaluationParams: evaluationParams = { + samplingInputs: evaluationParams.samplingInputs, + environment: Environment.mergeKeepSecond(evaluationParams.environment, newEnvironment), + evaluateNode: evaluationParams.evaluateNode, + } + evaluationParams.evaluateNode(newEvaluationParams, internals(t)) + } else { + Error("Wrong number of variables") + } +} + +module SamplingDistribution = { + type t = [ + | #SymbolicDist(SymbolicDistTypes.symbolicDist) + | #RenderedDist(PointSetTypes.pointSetDist) + ] + + let isSamplingDistribution: node => bool = x => + switch x { + | #SymbolicDist(_) => true + | #RenderedDist(_) => true + | _ => false + } + + let fromNode: node => result = x => + switch x { + | #SymbolicDist(n) => Ok(#SymbolicDist(n)) + | #RenderedDist(n) => Ok(#RenderedDist(n)) + | _ => Error("Not valid type") + } + + let renderIfIsNotSamplingDistribution = (params, t): result => + !isSamplingDistribution(t) + ? switch Node.render(params, t) { + | Ok(r) => Ok(r) + | Error(e) => Error(e) + } + : Ok(t) + + let map = (~renderedDistFn, ~symbolicDistFn, node: node) => + node |> ( + x => + switch x { + | #RenderedDist(r) => Some(renderedDistFn(r)) + | #SymbolicDist(s) => Some(symbolicDistFn(s)) + | _ => None + } + ) + + let sampleN = n => + map(~renderedDistFn=PointSetDist.sampleNRendered(n), ~symbolicDistFn=SymbolicDist.T.sampleN(n)) + + let getCombinationSamples = (n, algebraicOp, t1: node, t2: node) => + switch (sampleN(n, t1), sampleN(n, t2)) { + | (Some(a), Some(b)) => + Some( + Belt.Array.zip(a, b) |> E.A.fmap(((a, b)) => Operation.Algebraic.toFn(algebraicOp, a, b)), + ) + | _ => None + } + + let combineShapesUsingSampling = ( + evaluationParams: evaluationParams, + algebraicOp, + t1: node, + t2: node, + ) => { + let i1 = renderIfIsNotSamplingDistribution(evaluationParams, t1) + let i2 = renderIfIsNotSamplingDistribution(evaluationParams, t2) + E.R.merge(i1, i2) |> E.R.bind(_, ((a, b)) => { + let samples = getCombinationSamples( + evaluationParams.samplingInputs.sampleCount, + algebraicOp, + a, + b, + ) + + 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") + pointSetDist |> E.R.fmap(r => #Normalize(#RenderedDist(r))) + }) + } +} diff --git a/packages/squiggle-lang/src/rescript/OldInterpreter/DistPlus.res b/packages/squiggle-lang/src/rescript/OldInterpreter/DistPlus.res new file mode 100644 index 00000000..2b1688b0 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/OldInterpreter/DistPlus.res @@ -0,0 +1,116 @@ +open PointSetTypes; + +@genType +type t = PointSetTypes.distPlus; + +let pointSetDistIntegral = pointSetDist => PointSetDist.T.Integral.get(pointSetDist); +let make = + ( + ~pointSetDist, + ~squiggleString, + (), + ) + : t => { + let integral = pointSetDistIntegral(pointSetDist); + {pointSetDist, integralCache: integral, squiggleString}; +}; + +let update = + ( + ~pointSetDist=?, + ~integralCache=?, + ~squiggleString=?, + t: t, + ) => { + pointSetDist: E.O.default(t.pointSetDist, pointSetDist), + integralCache: E.O.default(t.integralCache, integralCache), + squiggleString: E.O.default(t.squiggleString, squiggleString), +}; + +let updateShape = (pointSetDist, t) => { + let integralCache = pointSetDistIntegral(pointSetDist); + update(~pointSetDist, ~integralCache, t); +}; + +let toPointSetDist = ({pointSetDist, _}: t) => pointSetDist; + +let pointSetDistFn = (fn, {pointSetDist}: t) => fn(pointSetDist); + +module T = + Distributions.Dist({ + type t = PointSetTypes.distPlus; + type integral = PointSetTypes.distPlus; + let toPointSetDist = toPointSetDist; + let toContinuous = pointSetDistFn(PointSetDist.T.toContinuous); + let toDiscrete = pointSetDistFn(PointSetDist.T.toDiscrete); + + let normalize = (t: t): t => { + let normalizedShape = t |> toPointSetDist |> PointSetDist.T.normalize; + t |> updateShape(normalizedShape); + }; + + let truncate = (leftCutoff, rightCutoff, t: t): t => { + let truncatedShape = + t + |> toPointSetDist + |> PointSetDist.T.truncate(leftCutoff, rightCutoff); + + t |> updateShape(truncatedShape); + }; + + let xToY = (f, t: t) => + t + |> toPointSetDist + |> PointSetDist.T.xToY(f); + + let minX = pointSetDistFn(PointSetDist.T.minX); + let maxX = pointSetDistFn(PointSetDist.T.maxX); + let toDiscreteProbabilityMassFraction = + pointSetDistFn(PointSetDist.T.toDiscreteProbabilityMassFraction); + + // This bit is kind of awkward, could probably use rethinking. + let integral = (t: t) => + updateShape(Continuous(t.integralCache), t); + + let updateIntegralCache = (integralCache: option, t) => + update(~integralCache=E.O.default(t.integralCache, integralCache), t); + + let downsample = (i, t): t => + updateShape(t |> toPointSetDist |> PointSetDist.T.downsample(i), t); + // todo: adjust for limit, maybe? + let mapY = + ( + ~integralSumCacheFn=previousIntegralSum => None, + ~integralCacheFn=previousIntegralCache => None, + ~fn, + {pointSetDist, _} as t: t, + ) + : t => + PointSetDist.T.mapY(~integralSumCacheFn, ~fn, pointSetDist) + |> updateShape(_, t); + + // get the total of everything + let integralEndY = (t: t) => { + PointSetDist.T.Integral.sum( + toPointSetDist(t), + ); + }; + + // TODO: Fix this below, obviously. Adjust for limits + let integralXtoY = (f, t: t) => { + PointSetDist.T.Integral.xToY( + f, + toPointSetDist(t), + ) + }; + + // TODO: This part is broken when there is a limit, if this is supposed to be taken into account. + let integralYtoX = (f, t: t) => { + PointSetDist.T.Integral.yToX(f, toPointSetDist(t)); + }; + + let mean = (t: t) => { + PointSetDist.T.mean(t.pointSetDist); + }; + let variance = (t: t) => PointSetDist.T.variance(t.pointSetDist); + }); diff --git a/packages/squiggle-lang/src/rescript/OldInterpreter/typeSystem/HardcodedFunctions.res b/packages/squiggle-lang/src/rescript/OldInterpreter/typeSystem/HardcodedFunctions.res new file mode 100644 index 00000000..cf8fe470 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/OldInterpreter/typeSystem/HardcodedFunctions.res @@ -0,0 +1,234 @@ +open TypeSystem + +let wrongInputsError = (r: array) => { + let inputs = r |> E.A.fmap(TypedValue.toString) |> Js.String.concatMany(_, ",") + Js.log3("Inputs were", inputs, r) + Error("Wrong inputs. The inputs were:" ++ inputs) +} + +let to_: (float, float) => result = (low, high) => + switch (low, high) { + | (low, high) if low <= 0.0 && low < high => + Ok(#SymbolicDist(SymbolicDist.Normal.from90PercentCI(low, high))) + | (low, high) if low < high => + Ok(#SymbolicDist(SymbolicDist.Lognormal.from90PercentCI(low, high))) + | (_, _) => Error("Low value must be less than high value.") + } + +let makeSymbolicFromTwoFloats = (name, fn) => + Function.T.make( + ~name, + ~outputType=#SamplingDistribution, + ~inputTypes=[#Float, #Float], + ~run=x => + switch x { + | [#Float(a), #Float(b)] => fn(a, b) |> E.R.fmap(r => (#SymbolicDist(r))) + | e => wrongInputsError(e) + }, + (), + ) + +let makeSymbolicFromOneFloat = (name, fn) => + Function.T.make( + ~name, + ~outputType=#SamplingDistribution, + ~inputTypes=[#Float], + ~run=x => + switch x { + | [#Float(a)] => fn(a) |> E.R.fmap(r => #SymbolicDist(r)) + | e => wrongInputsError(e) + }, + (), + ) + +let makeDistFloat = (name, fn) => + Function.T.make( + ~name, + ~outputType=#SamplingDistribution, + ~inputTypes=[#SamplingDistribution, #Float], + ~run=x => + switch x { + | [#SamplingDist(a), #Float(b)] => fn(a, b) + | [#RenderedDist(a), #Float(b)] => fn(#RenderedDist(a), b) + | e => wrongInputsError(e) + }, + (), + ) + +let makeRenderedDistFloat = (name, fn) => + Function.T.make( + ~name, + ~outputType=#RenderedDistribution, + ~inputTypes=[#RenderedDistribution, #Float], + ~shouldCoerceTypes=true, + ~run=x => + switch x { + | [#RenderedDist(a), #Float(b)] => fn(a, b) + | e => wrongInputsError(e) + }, + (), + ) + +let makeDist = (name, fn) => + Function.T.make( + ~name, + ~outputType=#SamplingDistribution, + ~inputTypes=[#SamplingDistribution], + ~run=x => + switch x { + | [#SamplingDist(a)] => fn(a) + | [#RenderedDist(a)] => fn(#RenderedDist(a)) + | e => wrongInputsError(e) + }, + (), + ) + +let floatFromDist = ( + distToFloatOp: Operation.distToFloatOperation, + t: TypeSystem.samplingDist, +): result => + switch t { + | #SymbolicDist(s) => + SymbolicDist.T.operate(distToFloatOp, s) |> E.R.bind(_, v => Ok(#SymbolicDist(#Float(v)))) + | #RenderedDist(rs) => PointSetDist.operate(distToFloatOp, rs) |> (v => Ok(#SymbolicDist(#Float(v)))) + } + +let verticalScaling = (scaleOp, rs, scaleBy) => { + // scaleBy has to be a single float, otherwise we'll return an error. + let fn = (secondary, main) => Operation.Scale.toFn(scaleOp, main, secondary) + let integralSumCacheFn = Operation.Scale.toIntegralSumCacheFn(scaleOp) + let integralCacheFn = Operation.Scale.toIntegralCacheFn(scaleOp) + Ok( + #RenderedDist( + PointSetDist.T.mapY( + ~integralSumCacheFn=integralSumCacheFn(scaleBy), + ~integralCacheFn=integralCacheFn(scaleBy), + ~fn=fn(scaleBy), + rs, + ), + ), + ) +} + +module Multimodal = { + let getByNameResult = Hash.getByNameResult + + let _paramsToDistsAndWeights = (r: array) => + switch r { + | [#Hash(r)] => + let dists = + getByNameResult(r, "dists") + ->E.R.bind(TypeSystem.TypedValue.toArray) + ->E.R.bind(r => r |> E.A.fmap(TypeSystem.TypedValue.toDist) |> E.A.R.firstErrorOrOpen) + let weights = + getByNameResult(r, "weights") + ->E.R.bind(TypeSystem.TypedValue.toArray) + ->E.R.bind(r => r |> E.A.fmap(TypeSystem.TypedValue.toFloat) |> E.A.R.firstErrorOrOpen) + + E.R.merge(dists, weights) -> E.R.bind(((a, b)) => + E.A.length(b) > E.A.length(a) ? + Error("Too many weights provided") : + Ok(E.A.zipMaxLength(a, b) |> E.A.fmap(((a, b)) => (a |> E.O.toExn(""), b |> E.O.default(1.0)))) + ) + | _ => Error("Needs items") + } + let _runner: array => result = r => { + let paramsToDistsAndWeights = + _paramsToDistsAndWeights(r) |> E.R.fmap( + E.A.fmap(((dist, weight)) => + #FunctionCall("scaleMultiply", [dist, #SymbolicDist(#Float(weight))]) + ), + ) + let pointwiseSum: result = + paramsToDistsAndWeights->E.R.bind(E.R.errorIfCondition(E.A.isEmpty, "Needs one input")) + |> E.R.fmap(r => + r + |> Js.Array.sliceFrom(1) + |> E.A.fold_left((acc, x) => #PointwiseCombination(#Add, acc, x), E.A.unsafe_get(r, 0)) + ) + pointwiseSum + } + + let _function = Function.T.make( + ~name="multimodal", + ~outputType=#SamplingDistribution, + ~inputTypes=[#Hash([("dists", #Array(#SamplingDistribution)), ("weights", #Array(#Float))])], + ~run=_runner, + (), + ) +} + +let all = [ + makeSymbolicFromTwoFloats("normal", SymbolicDist.Normal.make), + makeSymbolicFromTwoFloats("uniform", SymbolicDist.Uniform.make), + makeSymbolicFromTwoFloats("beta", SymbolicDist.Beta.make), + makeSymbolicFromTwoFloats("lognormal", SymbolicDist.Lognormal.make), + makeSymbolicFromTwoFloats("lognormalFromMeanAndStdDev", SymbolicDist.Lognormal.fromMeanAndStdev), + makeSymbolicFromOneFloat("exponential", SymbolicDist.Exponential.make), + Function.T.make( + ~name="to", + ~outputType=#SamplingDistribution, + ~inputTypes=[#Float, #Float], + ~run=x => + switch x { + | [#Float(a), #Float(b)] => to_(a, b) + | e => wrongInputsError(e) + }, + (), + ), + Function.T.make( + ~name="triangular", + ~outputType=#SamplingDistribution, + ~inputTypes=[#Float, #Float, #Float], + ~run=x => + switch x { + | [#Float(a), #Float(b), #Float(c)] => + SymbolicDist.Triangular.make(a, b, c) |> E.R.fmap(r => #SymbolicDist(r)) + | e => wrongInputsError(e) + }, + (), + ), + Function.T.make( + ~name="log", + ~outputType=#Float, + ~inputTypes=[#Float], + ~run=x => + switch x { + | [#Float(a)] => Ok(#SymbolicDist(#Float(Js.Math.log(a)))) + | e => wrongInputsError(e) + }, + (), + ), + makeDistFloat("pdf", (dist, float) => floatFromDist(#Pdf(float), dist)), + makeDistFloat("inv", (dist, float) => floatFromDist(#Inv(float), dist)), + makeDistFloat("cdf", (dist, float) => floatFromDist(#Cdf(float), dist)), + makeDist("mean", dist => floatFromDist(#Mean, dist)), + makeDist("sample", dist => floatFromDist(#Sample, dist)), + Function.T.make( + ~name="render", + ~outputType=#RenderedDistribution, + ~inputTypes=[#RenderedDistribution], + ~run=x => + switch x { + | [#RenderedDist(c)] => Ok(#RenderedDist(c)) + | e => wrongInputsError(e) + }, + (), + ), + Function.T.make( + ~name="normalize", + ~outputType=#SamplingDistribution, + ~inputTypes=[#SamplingDistribution], + ~run=x => + switch x { + | [#SamplingDist(#SymbolicDist(c))] => Ok(#SymbolicDist(c)) + | [#SamplingDist(#RenderedDist(c))] => Ok(#RenderedDist(PointSetDist.T.normalize(c))) + | e => wrongInputsError(e) + }, + (), + ), + makeRenderedDistFloat("scaleExp", (dist, float) => verticalScaling(#Exponentiate, 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/OldInterpreter/typeSystem/TypeSystem.res b/packages/squiggle-lang/src/rescript/OldInterpreter/typeSystem/TypeSystem.res new file mode 100644 index 00000000..51332106 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/OldInterpreter/typeSystem/TypeSystem.res @@ -0,0 +1,204 @@ +type node = ASTTypes.node +let getFloat = ASTTypes.Node.getFloat + +type samplingDist = [ + | #SymbolicDist(SymbolicDistTypes.symbolicDist) + | #RenderedDist(PointSetTypes.pointSetDist) +] + +type rec hashType = array<(string, _type)> +and _type = [ + | #Float + | #SamplingDistribution + | #RenderedDistribution + | #Array(_type) + | #Hash(hashType) +] + +type rec hashTypedValue = array<(string, typedValue)> +and typedValue = [ + | #Float(float) + | #RenderedDist(PointSetTypes.pointSetDist) + | #SamplingDist(samplingDist) + | #Array(array) + | #Hash(hashTypedValue) +] + +type _function = { + name: string, + inputTypes: array<_type>, + outputType: _type, + run: array => result, + shouldCoerceTypes: bool, +} + +type functions = array<_function> +type inputNodes = array + +module TypedValue = { + let rec toString: typedValue => string = x => + switch x { + | #SamplingDist(_) => "[sampling dist]" + | #RenderedDist(_) => "[rendered PointSetDist]" + | #Float(f) => "Float: " ++ Js.Float.toString(f) + | #Array(a) => "[" ++ ((a |> E.A.fmap(toString) |> Js.String.concatMany(_, ",")) ++ "]") + | #Hash(v) => + "{" ++ + ((v + |> E.A.fmap(((name, value)) => name ++ (":" ++ toString(value))) + |> Js.String.concatMany(_, ",")) ++ + "}") + } + + let rec fromNode = (node: node): result => + switch node { + | #SymbolicDist(#Float(r)) => Ok(#Float(r)) + | #SymbolicDist(s) => Ok(#SamplingDist(#SymbolicDist(s))) + | #RenderedDist(s) => Ok(#RenderedDist(s)) + | #Array(r) => r |> E.A.fmap(fromNode) |> E.A.R.firstErrorOrOpen |> E.R.fmap(r => #Array(r)) + | #Hash(hash) => + hash + |> E.A.fmap(((name, t)) => fromNode(t) |> E.R.fmap(r => (name, r))) + |> E.A.R.firstErrorOrOpen + |> E.R.fmap(r => #Hash(r)) + | e => Error("Wrong type: " ++ ASTTypes.Node.toString(e)) + } + + // todo: Arrays and hashes + let rec fromNodeWithTypeCoercion = (evaluationParams, _type: _type, node) => + switch (_type, node) { + | (#Float, _) => + switch getFloat(node) { + | Some(a) => Ok(#Float(a)) + | _ => Error("Type Error: Expected float.") + } + | (#SamplingDistribution, _) => + ASTTypes.SamplingDistribution.renderIfIsNotSamplingDistribution( + evaluationParams, + node, + ) |> E.R.bind(_, fromNode) + | (#RenderedDistribution, _) => + ASTTypes.Node.render(evaluationParams, node) |> E.R.bind(_, fromNode) + | (#Array(_type), #Array(b)) => + b + |> E.A.fmap(fromNodeWithTypeCoercion(evaluationParams, _type)) + |> E.A.R.firstErrorOrOpen + |> E.R.fmap(r => #Array(r)) + | (#Hash(named), #Hash(r)) => + let keyValues = + named |> E.A.fmap(((name, intendedType)) => ( + name, + intendedType, + Hash.getByName(r, name), + )) + let typedHash = + keyValues + |> E.A.fmap(((name, intendedType, optionNode)) => + switch optionNode { + | Some(node) => + fromNodeWithTypeCoercion(evaluationParams, intendedType, node) |> E.R.fmap(node => ( + name, + node, + )) + | None => Error("Hash parameter not present in hash.") + } + ) + |> E.A.R.firstErrorOrOpen + |> E.R.fmap(r => #Hash(r)) + typedHash + | _ => Error("fromNodeWithTypeCoercion error, sorry.") + } + + let toFloat: typedValue => result = x => + switch x { + | #Float(x) => Ok(x) + | _ => Error("Not a float") + } + + let toArray: typedValue => result, string> = x => + switch x { + | #Array(x) => Ok(x) + | _ => Error("Not an array") + } + + let toNamed: typedValue => result = x => + switch x { + | #Hash(x) => Ok(x) + | _ => Error("Not a named item") + } + + let toDist: typedValue => result = x => + switch x { + | #SamplingDist(#SymbolicDist(c)) => Ok(#SymbolicDist(c)) + | #SamplingDist(#RenderedDist(c)) => Ok(#RenderedDist(c)) + | #RenderedDist(c) => Ok(#RenderedDist(c)) + | #Float(x) => Ok(#SymbolicDist(#Float(x))) + | x => Error("Cannot be converted into a distribution: " ++ toString(x)) + } +} + +module Function = { + type t = _function + type ts = functions + + module T = { + let make = (~name, ~inputTypes, ~outputType, ~run, ~shouldCoerceTypes=true, _): t => { + name: name, + inputTypes: inputTypes, + outputType: outputType, + run: run, + shouldCoerceTypes: shouldCoerceTypes, + } + + let _inputLengthCheck = (inputNodes: inputNodes, t: t) => { + let expectedLength = E.A.length(t.inputTypes) + let actualLength = E.A.length(inputNodes) + expectedLength == actualLength + ? Ok(inputNodes) + : Error( + "Wrong number of inputs. Expected" ++ + ((expectedLength |> E.I.toString) ++ + (". Got:" ++ (actualLength |> E.I.toString))), + ) + } + + let _coerceInputNodes = (evaluationParams, inputTypes, shouldCoerce, inputNodes) => + Belt.Array.zip(inputTypes, inputNodes) + |> E.A.fmap(((def, input)) => + shouldCoerce + ? TypedValue.fromNodeWithTypeCoercion(evaluationParams, def, input) + : TypedValue.fromNode(input) + ) + |> E.A.R.firstErrorOrOpen + + let inputsToTypedValues = ( + evaluationParams: ASTTypes.evaluationParams, + inputNodes: inputNodes, + t: t, + ) => + _inputLengthCheck(inputNodes, t)->E.R.bind( + _coerceInputNodes(evaluationParams, t.inputTypes, t.shouldCoerceTypes), + ) + + let run = ( + evaluationParams: ASTTypes.evaluationParams, + inputNodes: inputNodes, + t: t, + ) => + inputsToTypedValues(evaluationParams, inputNodes, t)->E.R.bind(t.run) + |> ( + x => + switch x { + | Ok(i) => Ok(i) + | Error(r) => Error("Function " ++ (t.name ++ (" error: " ++ r))) + } + ) + } + + module Ts = { + let findByName = (ts: ts, n: string) => ts |> Belt.Array.getBy(_, ({name}) => name == n) + + let findByNameAndRun = (ts: ts, n: string, evaluationParams, inputTypes) => + findByName(ts, n) |> E.O.fmap(T.run(evaluationParams, inputTypes)) + } +} From 9b494462d46e73f78699e5cbd8330ff641b03db5 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Tue, 5 Apr 2022 15:13:45 -0400 Subject: [PATCH 6/9] Removed oldInterpreter --- .../src/rescript/oldInterpreter/AST.res | 24 -- .../rescript/oldInterpreter/ASTEvaluator.res | 257 ------------------ .../src/rescript/oldInterpreter/ASTTypes.res | 233 ---------------- .../src/rescript/oldInterpreter/DistPlus.res | 116 -------- .../typeSystem/HardcodedFunctions.res | 234 ---------------- .../oldInterpreter/typeSystem/TypeSystem.res | 204 -------------- 6 files changed, 1068 deletions(-) delete mode 100644 packages/squiggle-lang/src/rescript/oldInterpreter/AST.res delete mode 100644 packages/squiggle-lang/src/rescript/oldInterpreter/ASTEvaluator.res delete mode 100644 packages/squiggle-lang/src/rescript/oldInterpreter/ASTTypes.res delete mode 100644 packages/squiggle-lang/src/rescript/oldInterpreter/DistPlus.res delete mode 100644 packages/squiggle-lang/src/rescript/oldInterpreter/typeSystem/HardcodedFunctions.res delete mode 100644 packages/squiggle-lang/src/rescript/oldInterpreter/typeSystem/TypeSystem.res diff --git a/packages/squiggle-lang/src/rescript/oldInterpreter/AST.res b/packages/squiggle-lang/src/rescript/oldInterpreter/AST.res deleted file mode 100644 index 2dca6ffc..00000000 --- a/packages/squiggle-lang/src/rescript/oldInterpreter/AST.res +++ /dev/null @@ -1,24 +0,0 @@ -open ASTTypes - -let toString = ASTTypes.Node.toString - -let envs = (samplingInputs, environment) => { - samplingInputs: samplingInputs, - environment: environment, - evaluateNode: ASTEvaluator.toLeaf, -} - -let toLeaf = (samplingInputs, environment, node: node) => - ASTEvaluator.toLeaf(envs(samplingInputs, environment), node) - -let toPointSetDist = (samplingInputs, environment, node: node) => - switch toLeaf(samplingInputs, environment, node) { - | Ok(#RenderedDist(pointSetDist)) => Ok(pointSetDist) - | Ok(_) => Error("Rendering failed.") - | Error(e) => Error(e) - } - -let runFunction = (samplingInputs, environment, inputs, fn: ASTTypes.Function.t) => { - let params = envs(samplingInputs, environment) - ASTTypes.Function.run(params, inputs, fn) -} \ No newline at end of file diff --git a/packages/squiggle-lang/src/rescript/oldInterpreter/ASTEvaluator.res b/packages/squiggle-lang/src/rescript/oldInterpreter/ASTEvaluator.res deleted file mode 100644 index 44c5565e..00000000 --- a/packages/squiggle-lang/src/rescript/oldInterpreter/ASTEvaluator.res +++ /dev/null @@ -1,257 +0,0 @@ -open ASTTypes - -type tResult = node => result - -/* Given two random variables A and B, this returns the distribution - of a new variable that is the result of the operation on A and B. - For instance, normal(0, 1) + normal(1, 1) -> normal(1, 2). - In general, this is implemented via convolution. */ -module AlgebraicCombination = { - let tryAnalyticalSimplification = (operation, t1: node, t2: node) => - switch (operation, t1, t2) { - | (operation, #SymbolicDist(d1), #SymbolicDist(d2)) => - switch SymbolicDist.T.tryAnalyticalSimplification(d1, d2, operation) { - | #AnalyticalSolution(symbolicDist) => Ok(#SymbolicDist(symbolicDist)) - | #Error(er) => Error(er) - | #NoSolution => Ok(#AlgebraicCombination(operation, t1, t2)) - } - | _ => Ok(#AlgebraicCombination(operation, t1, t2)) - } - - let combinationByRendering = (evaluationParams, algebraicOp, t1: node, t2: node): result< - node, - string, - > => - E.R.merge( - Node.ensureIsRenderedAndGetShape(evaluationParams, t1), - Node.ensureIsRenderedAndGetShape(evaluationParams, t2), - ) |> E.R.fmap(((a, b)) => #RenderedDist(PointSetDist.combineAlgebraically(algebraicOp, a, b))) - - let nodeScore: node => int = x => - switch x { - | #SymbolicDist(#Float(_)) => 1 - | #SymbolicDist(_) => 1000 - | #RenderedDist(Discrete(m)) => m.xyShape |> XYShape.T.length - | #RenderedDist(Mixed(_)) => 1000 - | #RenderedDist(Continuous(_)) => 1000 - | _ => 1000 - } - - let choose = (t1: node, t2: node) => - nodeScore(t1) * nodeScore(t2) > 10000 ? #Sampling : #Analytical - - let combine = (evaluationParams, algebraicOp, t1: node, t2: node): result => - E.R.merge( - ASTTypes.SamplingDistribution.renderIfIsNotSamplingDistribution(evaluationParams, t1), - ASTTypes.SamplingDistribution.renderIfIsNotSamplingDistribution(evaluationParams, t2), - ) |> E.R.bind(_, ((a, b)) => - switch choose(a, b) { - | #Sampling => - ASTTypes.SamplingDistribution.combineShapesUsingSampling( - evaluationParams, - algebraicOp, - a, - b, - ) - | #Analytical => combinationByRendering(evaluationParams, algebraicOp, a, b) - } - ) - - let operationToLeaf = ( - evaluationParams: evaluationParams, - algebraicOp: Operation.algebraicOperation, - t1: node, - t2: node, - ): result => - algebraicOp - |> tryAnalyticalSimplification(_, t1, t2) - |> E.R.bind(_, x => - switch x { - | #SymbolicDist(_) as t => Ok(t) - | _ => combine(evaluationParams, algebraicOp, t1, t2) - } - ) -} - -module PointwiseCombination = { - //TODO: This is crude and slow. It forces everything to be pointSetDist, even though much - //of the process could happen on symbolic distributions without a conversion to be a pointSetDist. - let pointwiseAdd = (evaluationParams: evaluationParams, t1: node, t2: node) => - switch (Node.render(evaluationParams, t1), Node.render(evaluationParams, t2)) { - | (Ok(#RenderedDist(rs1)), Ok(#RenderedDist(rs2))) => - Ok( - #RenderedDist( - PointSetDist.combinePointwise( - ~integralSumCachesFn=(a, b) => Some(a +. b), - ~integralCachesFn=(a, b) => Some( - Continuous.combinePointwise(~distributionType=#CDF, \"+.", a, b), - ), - \"+.", - rs1, - rs2, - ), - ), - ) - | (Error(e1), _) => Error(e1) - | (_, Error(e2)) => Error(e2) - | _ => Error("Pointwise combination: rendering failed.") - } - - let pointwiseCombine = (fn, evaluationParams: evaluationParams, t1: node, t2: node) => - switch // TODO: construct a function that we can easily sample from, to construct - // a RenderedDist. Use the xMin and xMax of the rendered pointSetDists to tell the sampling function where to look. - // TODO: This should work for symbolic distributions too! - (Node.render(evaluationParams, t1), Node.render(evaluationParams, t2)) { - | (Ok(#RenderedDist(rs1)), Ok(#RenderedDist(rs2))) => - Ok(#RenderedDist(PointSetDist.combinePointwise(fn, rs1, rs2))) - | (Error(e1), _) => Error(e1) - | (_, Error(e2)) => Error(e2) - | _ => Error("Pointwise combination: rendering failed.") - } - - let operationToLeaf = ( - evaluationParams: evaluationParams, - pointwiseOp: Operation.pointwiseOperation, - t1: node, - t2: node, - ) => - switch pointwiseOp { - | #Add => pointwiseAdd(evaluationParams, t1, t2) - | #Multiply => pointwiseCombine(\"*.", evaluationParams, t1, t2) - | #Exponentiate => pointwiseCombine(\"**", evaluationParams, t1, t2) - } -} - -module Truncate = { - type simplificationResult = [ - | #Solution(ASTTypes.node) - | #Error(string) - | #NoSolution - ] - - let trySimplification = (leftCutoff, rightCutoff, t): simplificationResult => - switch (leftCutoff, rightCutoff, t) { - | (None, None, t) => #Solution(t) - | (Some(lc), Some(rc), _) if lc > rc => - #Error("Left truncation bound must be smaller than right truncation bound.") - | (lc, rc, #SymbolicDist(#Uniform(u))) => - #Solution(#SymbolicDist(#Uniform(SymbolicDist.Uniform.truncate(lc, rc, u)))) - | _ => #NoSolution - } - - let truncateAsShape = (evaluationParams: evaluationParams, leftCutoff, rightCutoff, t) => - switch // TODO: use named args for xMin/xMax in renderToShape; if we're lucky we can at least get the tail - // of a distribution we otherwise wouldn't get at all - Node.ensureIsRendered(evaluationParams, t) { - | Ok(#RenderedDist(rs)) => - Ok(#RenderedDist(PointSetDist.T.truncate(leftCutoff, rightCutoff, rs))) - | Error(e) => Error(e) - | _ => Error("Could not truncate distribution.") - } - - let operationToLeaf = ( - evaluationParams, - leftCutoff: option, - rightCutoff: option, - t: node, - ): result => - t - |> trySimplification(leftCutoff, rightCutoff) - |> ( - x => - switch x { - | #Solution(t) => Ok(t) - | #Error(e) => Error(e) - | #NoSolution => truncateAsShape(evaluationParams, leftCutoff, rightCutoff, t) - } - ) -} - -module Normalize = { - let rec operationToLeaf = (evaluationParams, t: node): result => - switch t { - | #RenderedDist(s) => Ok(#RenderedDist(PointSetDist.T.normalize(s))) - | #SymbolicDist(_) => Ok(t) - | _ => ASTTypes.Node.evaluateAndRetry(evaluationParams, operationToLeaf, t) - } -} - -module FunctionCall = { - let _runHardcodedFunction = (name, evaluationParams, args) => - TypeSystem.Function.Ts.findByNameAndRun(HardcodedFunctions.all, name, evaluationParams, args) - - let _runLocalFunction = (name, evaluationParams: evaluationParams, args) => - Environment.getFunction(evaluationParams.environment, name) |> E.R.bind(_, ((argNames, fn)) => - ASTTypes.Function.run(evaluationParams, args, (argNames, fn)) - ) - - let _runWithEvaluatedInputs = ( - evaluationParams: ASTTypes.evaluationParams, - name, - args: array, - ) => - _runHardcodedFunction(name, evaluationParams, args) |> E.O.default( - _runLocalFunction(name, evaluationParams, args), - ) - - // TODO: This forces things to be floats - let run = (evaluationParams, name, args) => - args - |> E.A.fmap(a => evaluationParams.evaluateNode(evaluationParams, a)) - |> E.A.R.firstErrorOrOpen - |> E.R.bind(_, _runWithEvaluatedInputs(evaluationParams, name)) -} - -module Render = { - let rec operationToLeaf = (evaluationParams: evaluationParams, t: node): result => - switch t { - | #Function(_) => Error("Cannot render a function") - | #SymbolicDist(d) => - Ok( - #RenderedDist( - SymbolicDist.T.toPointSetDist(evaluationParams.samplingInputs.pointSetDistLength, d), - ), - ) - | #RenderedDist(_) as t => Ok(t) // already a rendered pointSetDist, we're done here - | _ => ASTTypes.Node.evaluateAndRetry(evaluationParams, operationToLeaf, t) - } -} - -/* This function recursively goes through the nodes of the parse tree, - replacing each Operation node and its subtree with a Data node. - Whenever possible, the replacement produces a new Symbolic Data node, - but most often it will produce a RenderedDist. - This function is used mainly to turn a parse tree into a single RenderedDist - that can then be displayed to the user. */ -let rec toLeaf = (evaluationParams: ASTTypes.evaluationParams, node: node): result => - switch node { - // Leaf nodes just stay leaf nodes - | #SymbolicDist(_) - | #Function(_) - | #RenderedDist(_) => - Ok(node) - | #Array(args) => - args |> E.A.fmap(toLeaf(evaluationParams)) |> E.A.R.firstErrorOrOpen |> E.R.fmap(r => #Array(r)) - // Operations nevaluationParamsd to be turned into leaves - | #AlgebraicCombination(algebraicOp, t1, t2) => - AlgebraicCombination.operationToLeaf(evaluationParams, algebraicOp, t1, t2) - | #PointwiseCombination(pointwiseOp, t1, t2) => - PointwiseCombination.operationToLeaf(evaluationParams, pointwiseOp, t1, t2) - | #Truncate(leftCutoff, rightCutoff, t) => - Truncate.operationToLeaf(evaluationParams, leftCutoff, rightCutoff, t) - | #Normalize(t) => Normalize.operationToLeaf(evaluationParams, t) - | #Render(t) => Render.operationToLeaf(evaluationParams, t) - | #Hash(t) => - t - |> E.A.fmap(((name: string, node: node)) => - toLeaf(evaluationParams, node) |> E.R.fmap(r => (name, r)) - ) - |> E.A.R.firstErrorOrOpen - |> E.R.fmap(r => #Hash(r)) - | #Symbol(r) => - ASTTypes.Environment.get(evaluationParams.environment, r) - |> E.O.toResult("Undeclared variable " ++ r) - |> E.R.bind(_, toLeaf(evaluationParams)) - | #FunctionCall(name, args) => - FunctionCall.run(evaluationParams, name, args) |> E.R.bind(_, toLeaf(evaluationParams)) - } diff --git a/packages/squiggle-lang/src/rescript/oldInterpreter/ASTTypes.res b/packages/squiggle-lang/src/rescript/oldInterpreter/ASTTypes.res deleted file mode 100644 index 31217374..00000000 --- a/packages/squiggle-lang/src/rescript/oldInterpreter/ASTTypes.res +++ /dev/null @@ -1,233 +0,0 @@ -@genType -type rec hash = array<(string, node)> -and node = [ - | #SymbolicDist(SymbolicDistTypes.symbolicDist) - | #RenderedDist(PointSetTypes.pointSetDist) - | #Symbol(string) - | #Hash(hash) - | #Array(array) - | #Function(array, node) - | #AlgebraicCombination(Operation.algebraicOperation, node, node) - | #PointwiseCombination(Operation.pointwiseOperation, node, node) - | #Normalize(node) - | #Render(node) - | #Truncate(option, option, node) - | #FunctionCall(string, array) -] - -type statement = [ - | #Assignment(string, node) - | #Expression(node) -] -type program = array - -type environment = Belt.Map.String.t - -type rec evaluationParams = { - samplingInputs: SamplingInputs.samplingInputs, - environment: environment, - evaluateNode: (evaluationParams, node) => Belt.Result.t, -} - -module Environment = { - type t = environment - module MS = Belt.Map.String - let fromArray = MS.fromArray - let empty: t = []->fromArray - let mergeKeepSecond = (a: t, b: t) => - MS.merge(a, b, (_, a, b) => - switch (a, b) { - | (_, Some(b)) => Some(b) - | (Some(a), _) => Some(a) - | _ => None - } - ) - let update = (t, str, fn) => MS.update(t, str, fn) - let get = (t: t, str) => MS.get(t, str) - let getFunction = (t: t, str) => - switch get(t, str) { - | Some(#Function(argNames, fn)) => Ok((argNames, fn)) - | _ => Error("Function " ++ (str ++ " not found")) - } -} - -module Node = { - let getFloat = (node: node) => - node |> ( - x => - switch x { - | #RenderedDist(Discrete({xyShape: {xs: [x], ys: [1.0]}})) => Some(x) - | #SymbolicDist(#Float(x)) => Some(x) - | _ => None - } - ) - - let evaluate = (evaluationParams: evaluationParams) => - evaluationParams.evaluateNode(evaluationParams) - - let evaluateAndRetry = (evaluationParams, fn, node) => - node |> evaluationParams.evaluateNode(evaluationParams) |> E.R.bind(_, fn(evaluationParams)) - - let rec toString: node => string = x => - switch x { - | #SymbolicDist(d) => SymbolicDist.T.toString(d) - | #RenderedDist(_) => "[renderedShape]" - | #AlgebraicCombination(op, t1, t2) => - Operation.Algebraic.format(op, toString(t1), toString(t2)) - | #PointwiseCombination(op, t1, t2) => - Operation.Pointwise.format(op, toString(t1), toString(t2)) - | #Normalize(t) => "normalize(k" ++ (toString(t) ++ ")") - | #Truncate(lc, rc, t) => Operation.Truncate.toString(lc, rc, toString(t)) - | #Render(t) => toString(t) - | #Symbol(t) => "Symbol: " ++ t - | #FunctionCall(name, args) => - "[Function call: (" ++ - (name ++ - ((args |> E.A.fmap(toString) |> Js.String.concatMany(_, ",")) ++ ")]")) - | #Function(args, internal) => - "[Function: (" ++ ((args |> Js.String.concatMany(_, ",")) ++ (toString(internal) ++ ")]")) - | #Array(a) => "[" ++ ((a |> E.A.fmap(toString) |> Js.String.concatMany(_, ",")) ++ "]") - | #Hash(h) => - "{" ++ - ((h - |> E.A.fmap(((name, value)) => name ++ (":" ++ toString(value))) - |> Js.String.concatMany(_, ",")) ++ - "}") - } - - let render = (evaluationParams: evaluationParams, r) => #Render(r) |> evaluate(evaluationParams) - - let ensureIsRendered = (params, t) => - switch t { - | #RenderedDist(_) => Ok(t) - | _ => - switch render(params, t) { - | Ok(#RenderedDist(r)) => Ok(#RenderedDist(r)) - | Ok(_) => Error("Did not render as requested") - | Error(e) => Error(e) - } - } - - let ensureIsRenderedAndGetShape = (params, t) => - switch ensureIsRendered(params, t) { - | Ok(#RenderedDist(r)) => Ok(r) - | Ok(_) => Error("Did not render as requested") - | Error(e) => Error(e) - } - - let toPointSetDist = (item: node) => - switch item { - | #RenderedDist(r) => Some(r) - | _ => None - } - - let _toFloat = (t: PointSetTypes.pointSetDist) => - switch t { - | Discrete({xyShape: {xs: [x], ys: [1.0]}}) => Some(#SymbolicDist(#Float(x))) - | _ => None - } - - let toFloat = (item: node): result => - item |> toPointSetDist |> E.O.bind(_, _toFloat) |> E.O.toResult("Not valid shape") -} - -module Function = { - type t = (array, node) - let fromNode: node => option = node => - switch node { - | #Function(r) => Some(r) - | _ => None - } - let argumentNames = ((a, _): t) => a - let internals = ((_, b): t) => b - let run = (evaluationParams: evaluationParams, args: array, t: t) => - if E.A.length(args) == E.A.length(argumentNames(t)) { - let newEnvironment = Belt.Array.zip(argumentNames(t), args) |> Environment.fromArray - let newEvaluationParams: evaluationParams = { - samplingInputs: evaluationParams.samplingInputs, - environment: Environment.mergeKeepSecond(evaluationParams.environment, newEnvironment), - evaluateNode: evaluationParams.evaluateNode, - } - evaluationParams.evaluateNode(newEvaluationParams, internals(t)) - } else { - Error("Wrong number of variables") - } -} - -module SamplingDistribution = { - type t = [ - | #SymbolicDist(SymbolicDistTypes.symbolicDist) - | #RenderedDist(PointSetTypes.pointSetDist) - ] - - let isSamplingDistribution: node => bool = x => - switch x { - | #SymbolicDist(_) => true - | #RenderedDist(_) => true - | _ => false - } - - let fromNode: node => result = x => - switch x { - | #SymbolicDist(n) => Ok(#SymbolicDist(n)) - | #RenderedDist(n) => Ok(#RenderedDist(n)) - | _ => Error("Not valid type") - } - - let renderIfIsNotSamplingDistribution = (params, t): result => - !isSamplingDistribution(t) - ? switch Node.render(params, t) { - | Ok(r) => Ok(r) - | Error(e) => Error(e) - } - : Ok(t) - - let map = (~renderedDistFn, ~symbolicDistFn, node: node) => - node |> ( - x => - switch x { - | #RenderedDist(r) => Some(renderedDistFn(r)) - | #SymbolicDist(s) => Some(symbolicDistFn(s)) - | _ => None - } - ) - - let sampleN = n => - map(~renderedDistFn=PointSetDist.sampleNRendered(n), ~symbolicDistFn=SymbolicDist.T.sampleN(n)) - - let getCombinationSamples = (n, algebraicOp, t1: node, t2: node) => - switch (sampleN(n, t1), sampleN(n, t2)) { - | (Some(a), Some(b)) => - Some( - Belt.Array.zip(a, b) |> E.A.fmap(((a, b)) => Operation.Algebraic.toFn(algebraicOp, a, b)), - ) - | _ => None - } - - let combineShapesUsingSampling = ( - evaluationParams: evaluationParams, - algebraicOp, - t1: node, - t2: node, - ) => { - let i1 = renderIfIsNotSamplingDistribution(evaluationParams, t1) - let i2 = renderIfIsNotSamplingDistribution(evaluationParams, t2) - E.R.merge(i1, i2) |> E.R.bind(_, ((a, b)) => { - let samples = getCombinationSamples( - evaluationParams.samplingInputs.sampleCount, - algebraicOp, - a, - b, - ) - - 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") - pointSetDist |> E.R.fmap(r => #Normalize(#RenderedDist(r))) - }) - } -} diff --git a/packages/squiggle-lang/src/rescript/oldInterpreter/DistPlus.res b/packages/squiggle-lang/src/rescript/oldInterpreter/DistPlus.res deleted file mode 100644 index 2b1688b0..00000000 --- a/packages/squiggle-lang/src/rescript/oldInterpreter/DistPlus.res +++ /dev/null @@ -1,116 +0,0 @@ -open PointSetTypes; - -@genType -type t = PointSetTypes.distPlus; - -let pointSetDistIntegral = pointSetDist => PointSetDist.T.Integral.get(pointSetDist); -let make = - ( - ~pointSetDist, - ~squiggleString, - (), - ) - : t => { - let integral = pointSetDistIntegral(pointSetDist); - {pointSetDist, integralCache: integral, squiggleString}; -}; - -let update = - ( - ~pointSetDist=?, - ~integralCache=?, - ~squiggleString=?, - t: t, - ) => { - pointSetDist: E.O.default(t.pointSetDist, pointSetDist), - integralCache: E.O.default(t.integralCache, integralCache), - squiggleString: E.O.default(t.squiggleString, squiggleString), -}; - -let updateShape = (pointSetDist, t) => { - let integralCache = pointSetDistIntegral(pointSetDist); - update(~pointSetDist, ~integralCache, t); -}; - -let toPointSetDist = ({pointSetDist, _}: t) => pointSetDist; - -let pointSetDistFn = (fn, {pointSetDist}: t) => fn(pointSetDist); - -module T = - Distributions.Dist({ - type t = PointSetTypes.distPlus; - type integral = PointSetTypes.distPlus; - let toPointSetDist = toPointSetDist; - let toContinuous = pointSetDistFn(PointSetDist.T.toContinuous); - let toDiscrete = pointSetDistFn(PointSetDist.T.toDiscrete); - - let normalize = (t: t): t => { - let normalizedShape = t |> toPointSetDist |> PointSetDist.T.normalize; - t |> updateShape(normalizedShape); - }; - - let truncate = (leftCutoff, rightCutoff, t: t): t => { - let truncatedShape = - t - |> toPointSetDist - |> PointSetDist.T.truncate(leftCutoff, rightCutoff); - - t |> updateShape(truncatedShape); - }; - - let xToY = (f, t: t) => - t - |> toPointSetDist - |> PointSetDist.T.xToY(f); - - let minX = pointSetDistFn(PointSetDist.T.minX); - let maxX = pointSetDistFn(PointSetDist.T.maxX); - let toDiscreteProbabilityMassFraction = - pointSetDistFn(PointSetDist.T.toDiscreteProbabilityMassFraction); - - // This bit is kind of awkward, could probably use rethinking. - let integral = (t: t) => - updateShape(Continuous(t.integralCache), t); - - let updateIntegralCache = (integralCache: option, t) => - update(~integralCache=E.O.default(t.integralCache, integralCache), t); - - let downsample = (i, t): t => - updateShape(t |> toPointSetDist |> PointSetDist.T.downsample(i), t); - // todo: adjust for limit, maybe? - let mapY = - ( - ~integralSumCacheFn=previousIntegralSum => None, - ~integralCacheFn=previousIntegralCache => None, - ~fn, - {pointSetDist, _} as t: t, - ) - : t => - PointSetDist.T.mapY(~integralSumCacheFn, ~fn, pointSetDist) - |> updateShape(_, t); - - // get the total of everything - let integralEndY = (t: t) => { - PointSetDist.T.Integral.sum( - toPointSetDist(t), - ); - }; - - // TODO: Fix this below, obviously. Adjust for limits - let integralXtoY = (f, t: t) => { - PointSetDist.T.Integral.xToY( - f, - toPointSetDist(t), - ) - }; - - // TODO: This part is broken when there is a limit, if this is supposed to be taken into account. - let integralYtoX = (f, t: t) => { - PointSetDist.T.Integral.yToX(f, toPointSetDist(t)); - }; - - let mean = (t: t) => { - PointSetDist.T.mean(t.pointSetDist); - }; - let variance = (t: t) => PointSetDist.T.variance(t.pointSetDist); - }); diff --git a/packages/squiggle-lang/src/rescript/oldInterpreter/typeSystem/HardcodedFunctions.res b/packages/squiggle-lang/src/rescript/oldInterpreter/typeSystem/HardcodedFunctions.res deleted file mode 100644 index cf8fe470..00000000 --- a/packages/squiggle-lang/src/rescript/oldInterpreter/typeSystem/HardcodedFunctions.res +++ /dev/null @@ -1,234 +0,0 @@ -open TypeSystem - -let wrongInputsError = (r: array) => { - let inputs = r |> E.A.fmap(TypedValue.toString) |> Js.String.concatMany(_, ",") - Js.log3("Inputs were", inputs, r) - Error("Wrong inputs. The inputs were:" ++ inputs) -} - -let to_: (float, float) => result = (low, high) => - switch (low, high) { - | (low, high) if low <= 0.0 && low < high => - Ok(#SymbolicDist(SymbolicDist.Normal.from90PercentCI(low, high))) - | (low, high) if low < high => - Ok(#SymbolicDist(SymbolicDist.Lognormal.from90PercentCI(low, high))) - | (_, _) => Error("Low value must be less than high value.") - } - -let makeSymbolicFromTwoFloats = (name, fn) => - Function.T.make( - ~name, - ~outputType=#SamplingDistribution, - ~inputTypes=[#Float, #Float], - ~run=x => - switch x { - | [#Float(a), #Float(b)] => fn(a, b) |> E.R.fmap(r => (#SymbolicDist(r))) - | e => wrongInputsError(e) - }, - (), - ) - -let makeSymbolicFromOneFloat = (name, fn) => - Function.T.make( - ~name, - ~outputType=#SamplingDistribution, - ~inputTypes=[#Float], - ~run=x => - switch x { - | [#Float(a)] => fn(a) |> E.R.fmap(r => #SymbolicDist(r)) - | e => wrongInputsError(e) - }, - (), - ) - -let makeDistFloat = (name, fn) => - Function.T.make( - ~name, - ~outputType=#SamplingDistribution, - ~inputTypes=[#SamplingDistribution, #Float], - ~run=x => - switch x { - | [#SamplingDist(a), #Float(b)] => fn(a, b) - | [#RenderedDist(a), #Float(b)] => fn(#RenderedDist(a), b) - | e => wrongInputsError(e) - }, - (), - ) - -let makeRenderedDistFloat = (name, fn) => - Function.T.make( - ~name, - ~outputType=#RenderedDistribution, - ~inputTypes=[#RenderedDistribution, #Float], - ~shouldCoerceTypes=true, - ~run=x => - switch x { - | [#RenderedDist(a), #Float(b)] => fn(a, b) - | e => wrongInputsError(e) - }, - (), - ) - -let makeDist = (name, fn) => - Function.T.make( - ~name, - ~outputType=#SamplingDistribution, - ~inputTypes=[#SamplingDistribution], - ~run=x => - switch x { - | [#SamplingDist(a)] => fn(a) - | [#RenderedDist(a)] => fn(#RenderedDist(a)) - | e => wrongInputsError(e) - }, - (), - ) - -let floatFromDist = ( - distToFloatOp: Operation.distToFloatOperation, - t: TypeSystem.samplingDist, -): result => - switch t { - | #SymbolicDist(s) => - SymbolicDist.T.operate(distToFloatOp, s) |> E.R.bind(_, v => Ok(#SymbolicDist(#Float(v)))) - | #RenderedDist(rs) => PointSetDist.operate(distToFloatOp, rs) |> (v => Ok(#SymbolicDist(#Float(v)))) - } - -let verticalScaling = (scaleOp, rs, scaleBy) => { - // scaleBy has to be a single float, otherwise we'll return an error. - let fn = (secondary, main) => Operation.Scale.toFn(scaleOp, main, secondary) - let integralSumCacheFn = Operation.Scale.toIntegralSumCacheFn(scaleOp) - let integralCacheFn = Operation.Scale.toIntegralCacheFn(scaleOp) - Ok( - #RenderedDist( - PointSetDist.T.mapY( - ~integralSumCacheFn=integralSumCacheFn(scaleBy), - ~integralCacheFn=integralCacheFn(scaleBy), - ~fn=fn(scaleBy), - rs, - ), - ), - ) -} - -module Multimodal = { - let getByNameResult = Hash.getByNameResult - - let _paramsToDistsAndWeights = (r: array) => - switch r { - | [#Hash(r)] => - let dists = - getByNameResult(r, "dists") - ->E.R.bind(TypeSystem.TypedValue.toArray) - ->E.R.bind(r => r |> E.A.fmap(TypeSystem.TypedValue.toDist) |> E.A.R.firstErrorOrOpen) - let weights = - getByNameResult(r, "weights") - ->E.R.bind(TypeSystem.TypedValue.toArray) - ->E.R.bind(r => r |> E.A.fmap(TypeSystem.TypedValue.toFloat) |> E.A.R.firstErrorOrOpen) - - E.R.merge(dists, weights) -> E.R.bind(((a, b)) => - E.A.length(b) > E.A.length(a) ? - Error("Too many weights provided") : - Ok(E.A.zipMaxLength(a, b) |> E.A.fmap(((a, b)) => (a |> E.O.toExn(""), b |> E.O.default(1.0)))) - ) - | _ => Error("Needs items") - } - let _runner: array => result = r => { - let paramsToDistsAndWeights = - _paramsToDistsAndWeights(r) |> E.R.fmap( - E.A.fmap(((dist, weight)) => - #FunctionCall("scaleMultiply", [dist, #SymbolicDist(#Float(weight))]) - ), - ) - let pointwiseSum: result = - paramsToDistsAndWeights->E.R.bind(E.R.errorIfCondition(E.A.isEmpty, "Needs one input")) - |> E.R.fmap(r => - r - |> Js.Array.sliceFrom(1) - |> E.A.fold_left((acc, x) => #PointwiseCombination(#Add, acc, x), E.A.unsafe_get(r, 0)) - ) - pointwiseSum - } - - let _function = Function.T.make( - ~name="multimodal", - ~outputType=#SamplingDistribution, - ~inputTypes=[#Hash([("dists", #Array(#SamplingDistribution)), ("weights", #Array(#Float))])], - ~run=_runner, - (), - ) -} - -let all = [ - makeSymbolicFromTwoFloats("normal", SymbolicDist.Normal.make), - makeSymbolicFromTwoFloats("uniform", SymbolicDist.Uniform.make), - makeSymbolicFromTwoFloats("beta", SymbolicDist.Beta.make), - makeSymbolicFromTwoFloats("lognormal", SymbolicDist.Lognormal.make), - makeSymbolicFromTwoFloats("lognormalFromMeanAndStdDev", SymbolicDist.Lognormal.fromMeanAndStdev), - makeSymbolicFromOneFloat("exponential", SymbolicDist.Exponential.make), - Function.T.make( - ~name="to", - ~outputType=#SamplingDistribution, - ~inputTypes=[#Float, #Float], - ~run=x => - switch x { - | [#Float(a), #Float(b)] => to_(a, b) - | e => wrongInputsError(e) - }, - (), - ), - Function.T.make( - ~name="triangular", - ~outputType=#SamplingDistribution, - ~inputTypes=[#Float, #Float, #Float], - ~run=x => - switch x { - | [#Float(a), #Float(b), #Float(c)] => - SymbolicDist.Triangular.make(a, b, c) |> E.R.fmap(r => #SymbolicDist(r)) - | e => wrongInputsError(e) - }, - (), - ), - Function.T.make( - ~name="log", - ~outputType=#Float, - ~inputTypes=[#Float], - ~run=x => - switch x { - | [#Float(a)] => Ok(#SymbolicDist(#Float(Js.Math.log(a)))) - | e => wrongInputsError(e) - }, - (), - ), - makeDistFloat("pdf", (dist, float) => floatFromDist(#Pdf(float), dist)), - makeDistFloat("inv", (dist, float) => floatFromDist(#Inv(float), dist)), - makeDistFloat("cdf", (dist, float) => floatFromDist(#Cdf(float), dist)), - makeDist("mean", dist => floatFromDist(#Mean, dist)), - makeDist("sample", dist => floatFromDist(#Sample, dist)), - Function.T.make( - ~name="render", - ~outputType=#RenderedDistribution, - ~inputTypes=[#RenderedDistribution], - ~run=x => - switch x { - | [#RenderedDist(c)] => Ok(#RenderedDist(c)) - | e => wrongInputsError(e) - }, - (), - ), - Function.T.make( - ~name="normalize", - ~outputType=#SamplingDistribution, - ~inputTypes=[#SamplingDistribution], - ~run=x => - switch x { - | [#SamplingDist(#SymbolicDist(c))] => Ok(#SymbolicDist(c)) - | [#SamplingDist(#RenderedDist(c))] => Ok(#RenderedDist(PointSetDist.T.normalize(c))) - | e => wrongInputsError(e) - }, - (), - ), - makeRenderedDistFloat("scaleExp", (dist, float) => verticalScaling(#Exponentiate, 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/oldInterpreter/typeSystem/TypeSystem.res b/packages/squiggle-lang/src/rescript/oldInterpreter/typeSystem/TypeSystem.res deleted file mode 100644 index 51332106..00000000 --- a/packages/squiggle-lang/src/rescript/oldInterpreter/typeSystem/TypeSystem.res +++ /dev/null @@ -1,204 +0,0 @@ -type node = ASTTypes.node -let getFloat = ASTTypes.Node.getFloat - -type samplingDist = [ - | #SymbolicDist(SymbolicDistTypes.symbolicDist) - | #RenderedDist(PointSetTypes.pointSetDist) -] - -type rec hashType = array<(string, _type)> -and _type = [ - | #Float - | #SamplingDistribution - | #RenderedDistribution - | #Array(_type) - | #Hash(hashType) -] - -type rec hashTypedValue = array<(string, typedValue)> -and typedValue = [ - | #Float(float) - | #RenderedDist(PointSetTypes.pointSetDist) - | #SamplingDist(samplingDist) - | #Array(array) - | #Hash(hashTypedValue) -] - -type _function = { - name: string, - inputTypes: array<_type>, - outputType: _type, - run: array => result, - shouldCoerceTypes: bool, -} - -type functions = array<_function> -type inputNodes = array - -module TypedValue = { - let rec toString: typedValue => string = x => - switch x { - | #SamplingDist(_) => "[sampling dist]" - | #RenderedDist(_) => "[rendered PointSetDist]" - | #Float(f) => "Float: " ++ Js.Float.toString(f) - | #Array(a) => "[" ++ ((a |> E.A.fmap(toString) |> Js.String.concatMany(_, ",")) ++ "]") - | #Hash(v) => - "{" ++ - ((v - |> E.A.fmap(((name, value)) => name ++ (":" ++ toString(value))) - |> Js.String.concatMany(_, ",")) ++ - "}") - } - - let rec fromNode = (node: node): result => - switch node { - | #SymbolicDist(#Float(r)) => Ok(#Float(r)) - | #SymbolicDist(s) => Ok(#SamplingDist(#SymbolicDist(s))) - | #RenderedDist(s) => Ok(#RenderedDist(s)) - | #Array(r) => r |> E.A.fmap(fromNode) |> E.A.R.firstErrorOrOpen |> E.R.fmap(r => #Array(r)) - | #Hash(hash) => - hash - |> E.A.fmap(((name, t)) => fromNode(t) |> E.R.fmap(r => (name, r))) - |> E.A.R.firstErrorOrOpen - |> E.R.fmap(r => #Hash(r)) - | e => Error("Wrong type: " ++ ASTTypes.Node.toString(e)) - } - - // todo: Arrays and hashes - let rec fromNodeWithTypeCoercion = (evaluationParams, _type: _type, node) => - switch (_type, node) { - | (#Float, _) => - switch getFloat(node) { - | Some(a) => Ok(#Float(a)) - | _ => Error("Type Error: Expected float.") - } - | (#SamplingDistribution, _) => - ASTTypes.SamplingDistribution.renderIfIsNotSamplingDistribution( - evaluationParams, - node, - ) |> E.R.bind(_, fromNode) - | (#RenderedDistribution, _) => - ASTTypes.Node.render(evaluationParams, node) |> E.R.bind(_, fromNode) - | (#Array(_type), #Array(b)) => - b - |> E.A.fmap(fromNodeWithTypeCoercion(evaluationParams, _type)) - |> E.A.R.firstErrorOrOpen - |> E.R.fmap(r => #Array(r)) - | (#Hash(named), #Hash(r)) => - let keyValues = - named |> E.A.fmap(((name, intendedType)) => ( - name, - intendedType, - Hash.getByName(r, name), - )) - let typedHash = - keyValues - |> E.A.fmap(((name, intendedType, optionNode)) => - switch optionNode { - | Some(node) => - fromNodeWithTypeCoercion(evaluationParams, intendedType, node) |> E.R.fmap(node => ( - name, - node, - )) - | None => Error("Hash parameter not present in hash.") - } - ) - |> E.A.R.firstErrorOrOpen - |> E.R.fmap(r => #Hash(r)) - typedHash - | _ => Error("fromNodeWithTypeCoercion error, sorry.") - } - - let toFloat: typedValue => result = x => - switch x { - | #Float(x) => Ok(x) - | _ => Error("Not a float") - } - - let toArray: typedValue => result, string> = x => - switch x { - | #Array(x) => Ok(x) - | _ => Error("Not an array") - } - - let toNamed: typedValue => result = x => - switch x { - | #Hash(x) => Ok(x) - | _ => Error("Not a named item") - } - - let toDist: typedValue => result = x => - switch x { - | #SamplingDist(#SymbolicDist(c)) => Ok(#SymbolicDist(c)) - | #SamplingDist(#RenderedDist(c)) => Ok(#RenderedDist(c)) - | #RenderedDist(c) => Ok(#RenderedDist(c)) - | #Float(x) => Ok(#SymbolicDist(#Float(x))) - | x => Error("Cannot be converted into a distribution: " ++ toString(x)) - } -} - -module Function = { - type t = _function - type ts = functions - - module T = { - let make = (~name, ~inputTypes, ~outputType, ~run, ~shouldCoerceTypes=true, _): t => { - name: name, - inputTypes: inputTypes, - outputType: outputType, - run: run, - shouldCoerceTypes: shouldCoerceTypes, - } - - let _inputLengthCheck = (inputNodes: inputNodes, t: t) => { - let expectedLength = E.A.length(t.inputTypes) - let actualLength = E.A.length(inputNodes) - expectedLength == actualLength - ? Ok(inputNodes) - : Error( - "Wrong number of inputs. Expected" ++ - ((expectedLength |> E.I.toString) ++ - (". Got:" ++ (actualLength |> E.I.toString))), - ) - } - - let _coerceInputNodes = (evaluationParams, inputTypes, shouldCoerce, inputNodes) => - Belt.Array.zip(inputTypes, inputNodes) - |> E.A.fmap(((def, input)) => - shouldCoerce - ? TypedValue.fromNodeWithTypeCoercion(evaluationParams, def, input) - : TypedValue.fromNode(input) - ) - |> E.A.R.firstErrorOrOpen - - let inputsToTypedValues = ( - evaluationParams: ASTTypes.evaluationParams, - inputNodes: inputNodes, - t: t, - ) => - _inputLengthCheck(inputNodes, t)->E.R.bind( - _coerceInputNodes(evaluationParams, t.inputTypes, t.shouldCoerceTypes), - ) - - let run = ( - evaluationParams: ASTTypes.evaluationParams, - inputNodes: inputNodes, - t: t, - ) => - inputsToTypedValues(evaluationParams, inputNodes, t)->E.R.bind(t.run) - |> ( - x => - switch x { - | Ok(i) => Ok(i) - | Error(r) => Error("Function " ++ (t.name ++ (" error: " ++ r))) - } - ) - } - - module Ts = { - let findByName = (ts: ts, n: string) => ts |> Belt.Array.getBy(_, ({name}) => name == n) - - let findByNameAndRun = (ts: ts, n: string, evaluationParams, inputTypes) => - findByName(ts, n) |> E.O.fmap(T.run(evaluationParams, inputTypes)) - } -} From 6c282b0c7060221e76ca130b0af202d50e24a551 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Tue, 5 Apr 2022 15:23:39 -0400 Subject: [PATCH 7/9] Added genType to XYShape to fix tests --- packages/squiggle-lang/src/rescript/utility/XYShape.res | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/squiggle-lang/src/rescript/utility/XYShape.res b/packages/squiggle-lang/src/rescript/utility/XYShape.res index ec2df9f8..aba9ec80 100644 --- a/packages/squiggle-lang/src/rescript/utility/XYShape.res +++ b/packages/squiggle-lang/src/rescript/utility/XYShape.res @@ -1,12 +1,16 @@ +@genType type xyShape = { xs: array, ys: array, } +@genType type interpolationStrategy = [ | #Stepwise | #Linear ] + +@genType type extrapolationStrategy = [ | #UseZero | #UseOutermostPoints From d77f984af6fd92c181cae469566a6fb3d75f3db7 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Tue, 5 Apr 2022 15:32:06 -0400 Subject: [PATCH 8/9] utility -> Utility --- packages/squiggle-lang/src/rescript/{utility => Utility}/E.res | 0 packages/squiggle-lang/src/rescript/{utility => Utility}/Hash.res | 0 .../squiggle-lang/src/rescript/{utility => Utility}/Jstat.res | 0 .../squiggle-lang/src/rescript/{utility => Utility}/Lodash.res | 0 .../squiggle-lang/src/rescript/{utility => Utility}/Mathjs.res | 0 .../src/rescript/{utility => Utility}/MathjsWrapper.js | 0 .../squiggle-lang/src/rescript/{utility => Utility}/Operation.res | 0 .../src/rescript/{utility => Utility}/SamplingInputs.res | 0 .../src/rescript/{utility => Utility}/Sparklines.res | 0 .../squiggle-lang/src/rescript/{utility => Utility}/XYShape.res | 0 10 files changed, 0 insertions(+), 0 deletions(-) rename packages/squiggle-lang/src/rescript/{utility => Utility}/E.res (100%) rename packages/squiggle-lang/src/rescript/{utility => Utility}/Hash.res (100%) rename packages/squiggle-lang/src/rescript/{utility => Utility}/Jstat.res (100%) rename packages/squiggle-lang/src/rescript/{utility => Utility}/Lodash.res (100%) rename packages/squiggle-lang/src/rescript/{utility => Utility}/Mathjs.res (100%) rename packages/squiggle-lang/src/rescript/{utility => Utility}/MathjsWrapper.js (100%) rename packages/squiggle-lang/src/rescript/{utility => Utility}/Operation.res (100%) rename packages/squiggle-lang/src/rescript/{utility => Utility}/SamplingInputs.res (100%) rename packages/squiggle-lang/src/rescript/{utility => Utility}/Sparklines.res (100%) rename packages/squiggle-lang/src/rescript/{utility => Utility}/XYShape.res (100%) diff --git a/packages/squiggle-lang/src/rescript/utility/E.res b/packages/squiggle-lang/src/rescript/Utility/E.res similarity index 100% rename from packages/squiggle-lang/src/rescript/utility/E.res rename to packages/squiggle-lang/src/rescript/Utility/E.res diff --git a/packages/squiggle-lang/src/rescript/utility/Hash.res b/packages/squiggle-lang/src/rescript/Utility/Hash.res similarity index 100% rename from packages/squiggle-lang/src/rescript/utility/Hash.res rename to packages/squiggle-lang/src/rescript/Utility/Hash.res diff --git a/packages/squiggle-lang/src/rescript/utility/Jstat.res b/packages/squiggle-lang/src/rescript/Utility/Jstat.res similarity index 100% rename from packages/squiggle-lang/src/rescript/utility/Jstat.res rename to packages/squiggle-lang/src/rescript/Utility/Jstat.res diff --git a/packages/squiggle-lang/src/rescript/utility/Lodash.res b/packages/squiggle-lang/src/rescript/Utility/Lodash.res similarity index 100% rename from packages/squiggle-lang/src/rescript/utility/Lodash.res rename to packages/squiggle-lang/src/rescript/Utility/Lodash.res diff --git a/packages/squiggle-lang/src/rescript/utility/Mathjs.res b/packages/squiggle-lang/src/rescript/Utility/Mathjs.res similarity index 100% rename from packages/squiggle-lang/src/rescript/utility/Mathjs.res rename to packages/squiggle-lang/src/rescript/Utility/Mathjs.res diff --git a/packages/squiggle-lang/src/rescript/utility/MathjsWrapper.js b/packages/squiggle-lang/src/rescript/Utility/MathjsWrapper.js similarity index 100% rename from packages/squiggle-lang/src/rescript/utility/MathjsWrapper.js rename to packages/squiggle-lang/src/rescript/Utility/MathjsWrapper.js diff --git a/packages/squiggle-lang/src/rescript/utility/Operation.res b/packages/squiggle-lang/src/rescript/Utility/Operation.res similarity index 100% rename from packages/squiggle-lang/src/rescript/utility/Operation.res rename to packages/squiggle-lang/src/rescript/Utility/Operation.res diff --git a/packages/squiggle-lang/src/rescript/utility/SamplingInputs.res b/packages/squiggle-lang/src/rescript/Utility/SamplingInputs.res similarity index 100% rename from packages/squiggle-lang/src/rescript/utility/SamplingInputs.res rename to packages/squiggle-lang/src/rescript/Utility/SamplingInputs.res diff --git a/packages/squiggle-lang/src/rescript/utility/Sparklines.res b/packages/squiggle-lang/src/rescript/Utility/Sparklines.res similarity index 100% rename from packages/squiggle-lang/src/rescript/utility/Sparklines.res rename to packages/squiggle-lang/src/rescript/Utility/Sparklines.res diff --git a/packages/squiggle-lang/src/rescript/utility/XYShape.res b/packages/squiggle-lang/src/rescript/Utility/XYShape.res similarity index 100% rename from packages/squiggle-lang/src/rescript/utility/XYShape.res rename to packages/squiggle-lang/src/rescript/Utility/XYShape.res From c0118af31517407fdb14a73cf0229ba553b57781 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Tue, 5 Apr 2022 15:34:19 -0400 Subject: [PATCH 9/9] Changed warning comment --- .../Distributions/PointSetDist/AlgebraicShapeCombination.res | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/AlgebraicShapeCombination.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/AlgebraicShapeCombination.res index d94bd4a5..c0d85e60 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/AlgebraicShapeCombination.res +++ b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/AlgebraicShapeCombination.res @@ -118,7 +118,7 @@ let combineShapesContinuousContinuous = ( | #Logarithm => (m1, m2) => log(m1) /. log(m2) } // note: here, mInv2 = mean(1 / t2) ~= 1 / mean(t2) - // TODO: I don't know what the variances are for exponentatiation or logarithms + // TODO: Variances are for exponentatiation or logarithms are almost totally made up and very likely very wrong. // converts the variances and means of the two inputs into the variance of the output let combineVariancesFn = switch op { | #Add => (v1, v2, _, _) => v1 +. v2