Merge pull request #19 from QURIresearch/naming-refactor

File refactor
This commit is contained in:
Ozzie Gooen 2022-02-15 21:16:10 -05:00 committed by GitHub
commit 45017f3145
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 309 additions and 313 deletions

View File

@ -6,12 +6,12 @@ let makeTest = (~only=false, str, item1, item2) =>
? Only.test(str, () => expect(item1) -> toEqual(item2))
: test(str, () => expect(item1) -> toEqual(item2))
describe("DistTypes", () =>
describe("PointSetTypes", () =>
describe("Domain", () => {
let makeComplete = (yPoint, expectation) =>
makeTest(
"With input: " ++ Js.Float.toString(yPoint),
DistTypes.Domain.yPointToSubYPoint(Complete, yPoint),
PointSetTypes.Domain.yPointToSubYPoint(Complete, yPoint),
expectation,
)
let makeSingle = (direction: [#left | #right], excludingProbabilityMass, yPoint, expectation) =>
@ -19,7 +19,7 @@ describe("DistTypes", () =>
"Excluding: " ++
(Js.Float.toString(excludingProbabilityMass) ++
(" and yPoint: " ++ Js.Float.toString(yPoint))),
DistTypes.Domain.yPointToSubYPoint(
PointSetTypes.Domain.yPointToSubYPoint(
direction == #left
? LeftLimited({xPoint: 3.0, excludingProbabilityMass: excludingProbabilityMass})
: RightLimited({xPoint: 3.0, excludingProbabilityMass: excludingProbabilityMass}),
@ -28,7 +28,7 @@ describe("DistTypes", () =>
expectation,
)
let makeDouble = (domain, yPoint, expectation) =>
makeTest("Excluding: limits", DistTypes.Domain.yPointToSubYPoint(domain, yPoint), expectation)
makeTest("Excluding: limits", PointSetTypes.Domain.yPointToSubYPoint(domain, yPoint), expectation)
describe("With Complete Domain", () => {
makeComplete(0.0, Some(0.0))

View File

@ -1,7 +1,7 @@
open Jest
open Expect
let shape: DistTypes.xyShape = {xs: [1., 4., 8.], ys: [8., 9., 2.]}
// let PointSetDist: PointSetTypes.xyPointSetDist = {xs: [1., 4., 8.], ys: [8., 9., 2.]}
// let makeTest = (~only=false, str, item1, item2) =>
// only
@ -21,15 +21,15 @@ let shape: DistTypes.xyShape = {xs: [1., 4., 8.], ys: [8., 9., 2.]}
// expect(item1) |> toBeSoCloseTo(item2, ~digits)
// );
// describe("Shape", () => {
// describe("PointSetDist", () => {
// describe("Continuous", () => {
// open Continuous;
// let continuous = make(`Linear, shape, None);
// let continuous = make(`Linear, PointSetDist, None);
// makeTest("minX", T.minX(continuous), 1.0);
// makeTest("maxX", T.maxX(continuous), 8.0);
// makeTest(
// "mapY",
// T.mapY(r => r *. 2.0, continuous) |> getShape |> (r => r.ys),
// T.mapY(r => r *. 2.0, continuous) |> getPointSetDist |> (r => r.ys),
// [|16., 18.0, 4.0|],
// );
// describe("xToY", () => {
@ -57,7 +57,7 @@ let shape: DistTypes.xyShape = {xs: [1., 4., 8.], ys: [8., 9., 2.]}
// );
// });
// describe("when Stepwise", () => {
// let continuous = make(`Stepwise, shape, None);
// let continuous = make(`Stepwise, PointSetDist, None);
// makeTest(
// "at 4.0",
// T.xToY(4., continuous),
@ -82,7 +82,7 @@ let shape: DistTypes.xyShape = {xs: [1., 4., 8.], ys: [8., 9., 2.]}
// });
// makeTest(
// "integral",
// T.Integral.get(~cache=None, continuous) |> getShape,
// T.Integral.get(~cache=None, continuous) |> getPointSetDist,
// {xs: [|1.0, 4.0, 8.0|], ys: [|0.0, 25.5, 47.5|]},
// );
// makeTest(
@ -90,7 +90,7 @@ let shape: DistTypes.xyShape = {xs: [1., 4., 8.], ys: [8., 9., 2.]}
// {
// let continuous =
// make(`Stepwise, {xs: [|1., 4., 8.|], ys: [|0.1, 5., 1.0|]}, None);
// continuous |> toLinear |> E.O.fmap(getShape);
// continuous |> toLinear |> E.O.fmap(getPointSetDist);
// },
// Some({
// xs: [|1.00007, 1.00007, 4.0, 4.00007, 8.0, 8.00007|],
@ -101,7 +101,7 @@ let shape: DistTypes.xyShape = {xs: [1., 4., 8.], ys: [8., 9., 2.]}
// "toLinear",
// {
// let continuous = make(`Stepwise, {xs: [|0.0|], ys: [|0.3|]}, None);
// continuous |> toLinear |> E.O.fmap(getShape);
// continuous |> toLinear |> E.O.fmap(getPointSetDist);
// },
// Some({xs: [|0.0|], ys: [|0.3|]}),
// );
@ -131,16 +131,16 @@ let shape: DistTypes.xyShape = {xs: [1., 4., 8.], ys: [8., 9., 2.]}
// describe("Discrete", () => {
// open Discrete;
// let shape: DistTypes.xyShape = {
// let PointSetDist: PointSetTypes.xyPointSetDist = {
// xs: [|1., 4., 8.|],
// ys: [|0.3, 0.5, 0.2|],
// };
// let discrete = make(shape, None);
// let discrete = make(PointSetDist, None);
// makeTest("minX", T.minX(discrete), 1.0);
// makeTest("maxX", T.maxX(discrete), 8.0);
// makeTest(
// "mapY",
// T.mapY(r => r *. 2.0, discrete) |> (r => getShape(r).ys),
// T.mapY(r => r *. 2.0, discrete) |> (r => getPointSetDist(r).ys),
// [|0.6, 1.0, 0.4|],
// );
// makeTest(
@ -209,11 +209,11 @@ let shape: DistTypes.xyShape = {xs: [1., 4., 8.], ys: [8., 9., 2.]}
// describe("Mixed", () => {
// open Distributions.Mixed;
// let discreteShape: DistTypes.xyShape = {
// let discretePointSetDist: PointSetTypes.xyPointSetDist = {
// xs: [|1., 4., 8.|],
// ys: [|0.3, 0.5, 0.2|],
// };
// let discrete = Discrete.make(discreteShape, None);
// let discrete = Discrete.make(discretePointSetDist, None);
// let continuous =
// Continuous.make(
// `Linear,
@ -309,11 +309,11 @@ let shape: DistTypes.xyShape = {xs: [1., 4., 8.], ys: [8., 9., 2.]}
// describe("Distplus", () => {
// open DistPlus;
// let discreteShape: DistTypes.xyShape = {
// let discretePointSetDist: PointSetTypes.xyPointSetDist = {
// xs: [|1., 4., 8.|],
// ys: [|0.3, 0.5, 0.2|],
// };
// let discrete = Discrete.make(discreteShape, None);
// let discrete = Discrete.make(discretePointSetDist, None);
// let continuous =
// Continuous.make(
// `Linear,
@ -328,7 +328,7 @@ let shape: DistTypes.xyShape = {xs: [1., 4., 8.], ys: [8., 9., 2.]}
// );
// let distPlus =
// DistPlus.make(
// ~shape=Mixed(mixed),
// ~PointSetDist=Mixed(mixed),
// ~squiggleString=None,
// (),
// );
@ -376,38 +376,38 @@ let shape: DistTypes.xyShape = {xs: [1., 4., 8.], ys: [8., 9., 2.]}
// );
// });
// describe("Shape", () => {
// describe("PointSetDist", () => {
// let mean = 10.0;
// let stdev = 4.0;
// let variance = stdev ** 2.0;
// let numSamples = 10000;
// open Distributions.Shape;
// let normal: SymbolicTypes.symbolicDist = `Normal({mean, stdev});
// let normalShape = ExpressionTree.toShape(numSamples, `SymbolicDist(normal));
// open Distributions.PointSetDist;
// let normal: SymbolicDistTypes.symbolicDist = `Normal({mean, stdev});
// let normalPointSetDist = AST.toPointSetDist(numSamples, `SymbolicDist(normal));
// let lognormal = SymbolicDist.Lognormal.fromMeanAndStdev(mean, stdev);
// let lognormalShape = ExpressionTree.toShape(numSamples, `SymbolicDist(lognormal));
// let lognormalPointSetDist = AST.toPointSetDist(numSamples, `SymbolicDist(lognormal));
// makeTestCloseEquality(
// "Mean of a normal",
// T.mean(normalShape),
// T.mean(normalPointSetDist),
// mean,
// ~digits=2,
// );
// makeTestCloseEquality(
// "Variance of a normal",
// T.variance(normalShape),
// T.variance(normalPointSetDist),
// variance,
// ~digits=1,
// );
// makeTestCloseEquality(
// "Mean of a lognormal",
// T.mean(lognormalShape),
// T.mean(lognormalPointSetDist),
// mean,
// ~digits=2,
// );
// makeTestCloseEquality(
// "Variance of a lognormal",
// T.variance(lognormalShape),
// T.variance(lognormalPointSetDist),
// variance,
// ~digits=0,
// );

View File

@ -10,12 +10,12 @@ let makeTest = (~only=false, str, item1, item2) =>
expect(item1) |> toEqual(item2)
);
let evalParams: ExpressionTypes.ExpressionTree.evaluationParams = {
let evalParams: ASTTypes.AST.evaluationParams = {
samplingInputs: {
sampleCount: 1000,
outputXYPoints: 10000,
kernelWidth: None,
shapeLength: 1000,
PointSetDistLength: 1000,
},
environment:
[|
@ -25,12 +25,12 @@ let evalParams: ExpressionTypes.ExpressionTree.evaluationParams = {
("T", `SymbolicDist(`Float(1000000000000.0))),
|]
->Belt.Map.String.fromArray,
evaluateNode: ExpressionTreeEvaluator.toLeaf,
evaluateNode: ASTEvaluator.toLeaf,
};
let shape1: DistTypes.xyShape = {xs: [|1., 4., 8.|], ys: [|0.2, 0.4, 0.8|]};
let PointSetDist1: PointSetTypes.xyPointSetDist = {xs: [|1., 4., 8.|], ys: [|0.2, 0.4, 0.8|]};
describe("XYShapes", () => {
describe("XYPointSetDists", () => {
describe("logScorePoint", () => {
makeTest(
"When identical",

View File

@ -10,12 +10,12 @@ describe("Lodash", () =>
describe("Lodash", () => {
makeTest(
"split",
SamplesToShape.Internals.T.splitContinuousAndDiscrete([1.432, 1.33455, 2.0]),
SampleSet.Internals.T.splitContinuousAndDiscrete([1.432, 1.33455, 2.0]),
([1.432, 1.33455, 2.0], E.FloatFloatMap.empty()),
)
makeTest(
"split",
SamplesToShape.Internals.T.splitContinuousAndDiscrete([
SampleSet.Internals.T.splitContinuousAndDiscrete([
1.432,
1.33455,
2.0,
@ -32,13 +32,13 @@ describe("Lodash", () =>
E.A.concatMany([sorted, sorted, sorted, sorted]) |> Belt.SortArray.stableSortBy(_, compare)
}
let (_, discrete) = SamplesToShape.Internals.T.splitContinuousAndDiscrete(
let (_, discrete) = SampleSet.Internals.T.splitContinuousAndDiscrete(
makeDuplicatedArray(10),
)
let toArr = discrete |> E.FloatFloatMap.toArray
makeTest("splitMedium", toArr |> Belt.Array.length, 10)
let (c, discrete) = SamplesToShape.Internals.T.splitContinuousAndDiscrete(
let (c, discrete) = SampleSet.Internals.T.splitContinuousAndDiscrete(
makeDuplicatedArray(500),
)
let toArr = discrete |> E.FloatFloatMap.toArray

View File

@ -6,25 +6,25 @@ let makeTest = (~only=false, str, item1, item2) =>
? Only.test(str, () => expect(item1) -> toEqual(item2))
: test(str, () => expect(item1) -> toEqual(item2))
let shape1: DistTypes.xyShape = {xs: [1., 4., 8.], ys: [0.2, 0.4, 0.8]}
let pointSetDist1: PointSetTypes.xyShape = {xs: [1., 4., 8.], ys: [0.2, 0.4, 0.8]}
let shape2: DistTypes.xyShape = {
let pointSetDist2: PointSetTypes.xyShape = {
xs: [1., 5., 10.],
ys: [0.2, 0.5, 0.8],
}
let shape3: DistTypes.xyShape = {
let pointSetDist3: PointSetTypes.xyShape = {
xs: [1., 20., 50.],
ys: [0.2, 0.5, 0.8],
}
describe("XYShapes", () => {
describe("logScorePoint", () => {
makeTest("When identical", XYShape.logScorePoint(30, shape1, shape1), Some(0.0))
makeTest("When similar", XYShape.logScorePoint(30, shape1, shape2), Some(1.658971191043856))
makeTest("When identical", XYShape.logScorePoint(30, pointSetDist1, pointSetDist1), Some(0.0))
makeTest("When similar", XYShape.logScorePoint(30, pointSetDist1, pointSetDist2), Some(1.658971191043856))
makeTest(
"When very different",
XYShape.logScorePoint(30, shape1, shape3),
XYShape.logScorePoint(30, pointSetDist1, pointSetDist3),
Some(210.3721280423322),
)
})
@ -41,7 +41,7 @@ describe("XYShapes", () => {
describe("integrateWithTriangles", () =>
makeTest(
"integrates correctly",
XYShape.Range.integrateWithTriangles(shape1),
XYShape.Range.integrateWithTriangles(pointSetDist1),
Some({
xs: [1., 4., 8.],
ys: [0.0, 0.9000000000000001, 3.3000000000000007],

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,5 +0,0 @@
type t = ExpressionTypes.Program.program
let last = (r: t) => E.A.last(r) |> E.O.toResult("No rendered lines")
// let run = (p:program) => p |> E.A.last |> E.O.fmap(r =>
// )

View File

@ -1,3 +1,3 @@
const ProgramEvaluator = require('../distPlus/ProgramEvaluator.gen.js');
const ProgramEvaluator = require('../rescript/ProgramEvaluator.gen.js');
exports.runMePlease = ProgramEvaluator.runAll

View File

@ -5,7 +5,7 @@ module Inputs = {
sampleCount: option<int>,
outputXYPoints: option<int>,
kernelWidth: option<float>,
shapeLength: option<int>,
pointSetDistLength: option<int>,
}
}
let defaultRecommendedLength = 100
@ -14,20 +14,20 @@ module Inputs = {
type inputs = {
squiggleString: string,
samplingInputs: SamplingInputs.t,
environment: ExpressionTypes.ExpressionTree.environment,
environment: ASTTypes.AST.environment,
}
let empty: SamplingInputs.t = {
sampleCount: None,
outputXYPoints: None,
kernelWidth: None,
shapeLength: None,
pointSetDistLength: None,
}
let make = (
~samplingInputs=empty,
~squiggleString,
~environment=ExpressionTypes.ExpressionTree.Environment.empty,
~environment=ASTTypes.AST.Environment.empty,
(),
): inputs => {
samplingInputs: samplingInputs,
@ -40,8 +40,8 @@ type \"export" = [
| #DistPlus(DistPlus.t)
| #Float(float)
| #Function(
(array<string>, ExpressionTypes.ExpressionTree.node),
ExpressionTypes.ExpressionTree.environment,
(array<string>, ASTTypes.AST.node),
ASTTypes.AST.environment,
)
]
@ -53,28 +53,28 @@ module Internals = {
): Inputs.inputs => {
samplingInputs: samplingInputs,
squiggleString: squiggleString,
environment: ExpressionTypes.ExpressionTree.Environment.update(environment, str, _ => Some(
environment: ASTTypes.AST.Environment.update(environment, str, _ => Some(
node,
)),
}
type outputs = {
graph: ExpressionTypes.ExpressionTree.node,
shape: DistTypes.shape,
graph: ASTTypes.AST.node,
pointSetDist: PointSetTypes.pointSetDist,
}
let makeOutputs = (graph, shape): outputs => {graph: graph, shape: shape}
let makeOutputs = (graph, pointSetDist): outputs => {graph: graph, pointSetDist: pointSetDist}
let makeInputs = (inputs: Inputs.inputs): ExpressionTypes.ExpressionTree.samplingInputs => {
let makeInputs = (inputs: Inputs.inputs): ASTTypes.AST.samplingInputs => {
sampleCount: inputs.samplingInputs.sampleCount |> E.O.default(10000),
outputXYPoints: inputs.samplingInputs.outputXYPoints |> E.O.default(10000),
kernelWidth: inputs.samplingInputs.kernelWidth,
shapeLength: inputs.samplingInputs.shapeLength |> E.O.default(10000),
pointSetDistLength: inputs.samplingInputs.pointSetDistLength |> E.O.default(10000),
}
let runNode = (inputs, node) =>
ExpressionTree.toLeaf(makeInputs(inputs), inputs.environment, node)
AST.toLeaf(makeInputs(inputs), inputs.environment, node)
let runProgram = (inputs: Inputs.inputs, p: ExpressionTypes.Program.program) => {
let runProgram = (inputs: Inputs.inputs, p: ASTTypes.Program.program) => {
let ins = ref(inputs)
p
|> E.A.fmap(x =>
@ -91,14 +91,14 @@ module Internals = {
}
let inputsToLeaf = (inputs: Inputs.inputs) =>
MathJsParser.fromString(inputs.squiggleString) |> E.R.bind(_, g => runProgram(inputs, g))
Parser.fromString(inputs.squiggleString) |> E.R.bind(_, g => runProgram(inputs, g))
let outputToDistPlus = (inputs: Inputs.inputs, shape: DistTypes.shape) =>
DistPlus.make(~shape, ~squiggleString=Some(inputs.squiggleString), ())
let outputToDistPlus = (inputs: Inputs.inputs, pointSetDist: PointSetTypes.pointSetDist) =>
DistPlus.make(~pointSetDist, ~squiggleString=Some(inputs.squiggleString), ())
}
let renderIfNeeded = (inputs: Inputs.inputs, node: ExpressionTypes.ExpressionTree.node): result<
ExpressionTypes.ExpressionTree.node,
let renderIfNeeded = (inputs: Inputs.inputs, node: ASTTypes.AST.node): result<
ASTTypes.AST.node,
string,
> =>
node |> (
@ -121,11 +121,11 @@ let renderIfNeeded = (inputs: Inputs.inputs, node: ExpressionTypes.ExpressionTre
}
)
// TODO: Consider using ExpressionTypes.ExpressionTree.getFloat or similar in this function
// TODO: Consider using ASTTypes.AST.getFloat or similar in this function
let coersionToExportedTypes = (
inputs,
env: ExpressionTypes.ExpressionTree.environment,
node: ExpressionTypes.ExpressionTree.node,
env: ASTTypes.AST.environment,
node: ASTTypes.AST.node,
): result<\"export", string> =>
node
|> renderIfNeeded(inputs)
@ -135,7 +135,7 @@ let coersionToExportedTypes = (
| #SymbolicDist(#Float(x)) => Ok(#Float(x))
| #RenderedDist(n) => Ok(#DistPlus(Internals.outputToDistPlus(inputs, n)))
| #Function(n) => Ok(#Function(n, env))
| n => Error("Didn't output a rendered distribution. Format:" ++ ExpressionTree.toString(n))
| n => Error("Didn't output a rendered distribution. Format:" ++ AST.toString(n))
}
)
@ -160,10 +160,10 @@ let evaluateProgram = (inputs: Inputs.inputs) =>
let evaluateFunction = (
inputs: Inputs.inputs,
fn: (array<string>, ExpressionTypes.ExpressionTree.node),
fn: (array<string>, ASTTypes.AST.node),
fnInputs,
) => {
let output = ExpressionTree.runFunction(
let output = AST.runFunction(
Internals.makeInputs(inputs),
inputs.environment,
fnInputs,
@ -179,7 +179,7 @@ let runAll = (squiggleString: string) => {
sampleCount: Some(10000),
outputXYPoints: Some(10000),
kernelWidth: None,
shapeLength: Some(1000),
pointSetDistLength: Some(1000),
},
~squiggleString,
~environment=[]->Belt.Map.String.fromArray,

View File

@ -1,17 +1,19 @@
open ExpressionTypes.ExpressionTree
open ASTTypes.AST
let toString = ASTBasic.toString
let toString = ExpressionTreeBasic.toString
let envs = (samplingInputs, environment) => {
samplingInputs: samplingInputs,
environment: environment,
evaluateNode: ExpressionTreeEvaluator.toLeaf,
evaluateNode: ASTEvaluator.toLeaf,
}
let toLeaf = (samplingInputs, environment, node: node) =>
ExpressionTreeEvaluator.toLeaf(envs(samplingInputs, environment), node)
let toShape = (samplingInputs, environment, node: node) =>
ASTEvaluator.toLeaf(envs(samplingInputs, environment), node)
let toPointSetDist = (samplingInputs, environment, node: node) =>
switch toLeaf(samplingInputs, environment, node) {
| Ok(#RenderedDist(shape)) => Ok(shape)
| Ok(#RenderedDist(pointSetDist)) => Ok(pointSetDist)
| Ok(_) => Error("Rendering failed.")
| Error(e) => Error(e)
}

View File

@ -1,4 +1,5 @@
open ExpressionTypes.ExpressionTree
open ASTTypes.AST
// This file exists to manage a dependency cycle. It would be good to refactor later.
let rec toString: node => string = x =>
switch x {

View File

@ -1,5 +1,5 @@
open ExpressionTypes
open ExpressionTypes.ExpressionTree
open ASTTypes
open ASTTypes.AST
type t = node
type tResult = node => result<node, string>
@ -27,7 +27,7 @@ module AlgebraicCombination = {
E.R.merge(
Render.ensureIsRenderedAndGetShape(evaluationParams, t1),
Render.ensureIsRenderedAndGetShape(evaluationParams, t2),
) |> E.R.fmap(((a, b)) => #RenderedDist(Shape.combineAlgebraically(algebraicOp, a, b)))
) |> E.R.fmap(((a, b)) => #RenderedDist(PointSetDist.combineAlgebraically(algebraicOp, a, b)))
let nodeScore: node => int = x =>
switch x {
@ -56,7 +56,7 @@ module AlgebraicCombination = {
let operationToLeaf = (
evaluationParams: evaluationParams,
algebraicOp: ExpressionTypes.algebraicOperation,
algebraicOp: ASTTypes.algebraicOperation,
t1: t,
t2: t,
): result<node, string> =>
@ -76,7 +76,7 @@ module PointwiseCombination = {
| (Ok(#RenderedDist(rs1)), Ok(#RenderedDist(rs2))) =>
Ok(
#RenderedDist(
Shape.combinePointwise(
PointSetDist.combinePointwise(
~integralSumCachesFn=(a, b) => Some(a +. b),
~integralCachesFn=(a, b) => Some(
Continuous.combinePointwise(~distributionType=#CDF, \"+.", a, b),
@ -94,11 +94,11 @@ module PointwiseCombination = {
let pointwiseCombine = (fn, evaluationParams: evaluationParams, t1: t, t2: t) =>
switch // TODO: construct a function that we can easily sample from, to construct
// a RenderedDist. Use the xMin and xMax of the rendered shapes to tell the sampling function where to look.
// 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!
(Render.render(evaluationParams, t1), Render.render(evaluationParams, t2)) {
| (Ok(#RenderedDist(rs1)), Ok(#RenderedDist(rs2))) =>
Ok(#RenderedDist(Shape.combinePointwise(fn, rs1, rs2)))
Ok(#RenderedDist(PointSetDist.combinePointwise(fn, rs1, rs2)))
| (Error(e1), _) => Error(e1)
| (_, Error(e2)) => Error(e2)
| _ => Error("Pointwise combination: rendering failed.")
@ -132,7 +132,7 @@ module Truncate = {
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
Render.ensureIsRendered(evaluationParams, t) {
| Ok(#RenderedDist(rs)) => Ok(#RenderedDist(Shape.T.truncate(leftCutoff, rightCutoff, rs)))
| Ok(#RenderedDist(rs)) => Ok(#RenderedDist(PointSetDist.T.truncate(leftCutoff, rightCutoff, rs)))
| Error(e) => Error(e)
| _ => Error("Could not truncate distribution.")
}
@ -158,7 +158,7 @@ module Truncate = {
module Normalize = {
let rec operationToLeaf = (evaluationParams, t: node): result<node, string> =>
switch t {
| #RenderedDist(s) => Ok(#RenderedDist(Shape.T.normalize(s)))
| #RenderedDist(s) => Ok(#RenderedDist(PointSetDist.T.normalize(s)))
| #SymbolicDist(_) => Ok(t)
| _ => evaluateAndRetry(evaluationParams, operationToLeaf, t)
}
@ -174,9 +174,9 @@ module FunctionCall = {
)
let _runWithEvaluatedInputs = (
evaluationParams: ExpressionTypes.ExpressionTree.evaluationParams,
evaluationParams: ASTTypes.AST.evaluationParams,
name,
args: array<ExpressionTypes.ExpressionTree.node>,
args: array<ASTTypes.AST.node>,
) =>
_runHardcodedFunction(name, evaluationParams, args) |> E.O.default(
_runLocalFunction(name, evaluationParams, args),
@ -195,8 +195,8 @@ module Render = {
switch t {
| #Function(_) => Error("Cannot render a function")
| #SymbolicDist(d) =>
Ok(#RenderedDist(SymbolicDist.T.toShape(evaluationParams.samplingInputs.shapeLength, d)))
| #RenderedDist(_) as t => Ok(t) // already a rendered shape, we're done here
Ok(#RenderedDist(SymbolicDist.T.toPointSetDist(evaluationParams.samplingInputs.pointSetDistLength, d)))
| #RenderedDist(_) as t => Ok(t) // already a rendered pointSetDist, we're done here
| _ => evaluateAndRetry(evaluationParams, operationToLeaf, t)
}
}
@ -208,7 +208,7 @@ module Render = {
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: ExpressionTypes.ExpressionTree.evaluationParams,
evaluationParams: ASTTypes.AST.evaluationParams,
node: t,
): result<t, string> =>
switch node {
@ -236,7 +236,7 @@ let rec toLeaf = (
|> E.A.R.firstErrorOrOpen
|> E.R.fmap(r => #Hash(r))
| #Symbol(r) =>
ExpressionTypes.ExpressionTree.Environment.get(evaluationParams.environment, r)
ASTTypes.AST.Environment.get(evaluationParams.environment, r)
|> E.O.toResult("Undeclared variable " ++ r)
|> E.R.bind(_, toLeaf(evaluationParams))
| #FunctionCall(name, args) =>

View File

@ -15,11 +15,11 @@ type distToFloatOperation = [
| #Sample
]
module ExpressionTree = {
module AST = {
type rec hash = array<(string, node)>
and node = [
| #SymbolicDist(SymbolicTypes.symbolicDist)
| #RenderedDist(DistTypes.shape)
| #SymbolicDist(SymbolicDistTypes.symbolicDist)
| #RenderedDist(PointSetTypes.pointSetDist)
| #Symbol(string)
| #Hash(hash)
| #Array(array<node>)
@ -64,7 +64,7 @@ module ExpressionTree = {
sampleCount: int,
outputXYPoints: int,
kernelWidth: option<float>,
shapeLength: int,
pointSetDistLength: int,
}
module SamplingInputs = {
@ -72,13 +72,13 @@ module ExpressionTree = {
sampleCount: option<int>,
outputXYPoints: option<int>,
kernelWidth: option<float>,
shapeLength: option<int>,
pointSetDistLength: option<int>,
}
let withDefaults = (t: t): samplingInputs => {
sampleCount: t.sampleCount |> E.O.default(10000),
outputXYPoints: t.outputXYPoints |> E.O.default(10000),
kernelWidth: t.kernelWidth,
shapeLength: t.shapeLength |> E.O.default(10000),
pointSetDistLength: t.pointSetDistLength |> E.O.default(10000),
}
}
@ -148,7 +148,7 @@ module ExpressionTree = {
| _ => None
}
let _toFloat = (t: DistTypes.shape) =>
let _toFloat = (t: PointSetTypes.pointSetDist) =>
switch t {
| Discrete({xyShape: {xs: [x], ys: [1.0]}}) => Some(#SymbolicDist(#Float(x)))
| _ => None
@ -160,15 +160,15 @@ module ExpressionTree = {
}
type simplificationResult = [
| #Solution(ExpressionTree.node)
| #Solution(AST.node)
| #Error(string)
| #NoSolution
]
module Program = {
type statement = [
| #Assignment(string, ExpressionTree.node)
| #Expression(ExpressionTree.node)
| #Assignment(string, AST.node)
| #Expression(AST.node)
]
type program = array<statement>
}

View File

@ -1,4 +1,4 @@
open ExpressionTypes
open ASTTypes
module Algebraic = {
type t = algebraicOperation
@ -103,5 +103,5 @@ module T = {
| #Truncate(lc, rc, t) => truncateToString(lc, rc, nodeToString(t))
| #Render(t) => nodeToString(t)
| _ => ""
} // SymbolicDist and RenderedDist are handled in ExpressionTree.toString.
} // SymbolicDist and RenderedDist are handled in AST.toString.
}

View File

@ -1,4 +1,4 @@
open ExpressionTypes.ExpressionTree
open ASTTypes.AST
module Function = {
type t = (array<string>, node)
@ -10,7 +10,7 @@ module Function = {
let argumentNames = ((a, _): t) => a
let internals = ((_, b): t) => b
let run = (
evaluationParams: ExpressionTypes.ExpressionTree.evaluationParams,
evaluationParams: ASTTypes.AST.evaluationParams,
args: array<node>,
t: t,
) =>
@ -19,10 +19,10 @@ module Function = {
Belt.Array.zip(
argumentNames(t),
args,
) |> ExpressionTypes.ExpressionTree.Environment.fromArray
let newEvaluationParams: ExpressionTypes.ExpressionTree.evaluationParams = {
) |> ASTTypes.AST.Environment.fromArray
let newEvaluationParams: ASTTypes.AST.evaluationParams = {
samplingInputs: evaluationParams.samplingInputs,
environment: ExpressionTypes.ExpressionTree.Environment.mergeKeepSecond(
environment: ASTTypes.AST.Environment.mergeKeepSecond(
evaluationParams.environment,
newEnvironment,
),
@ -36,8 +36,8 @@ module Function = {
module Primative = {
type t = [
| #SymbolicDist(SymbolicTypes.symbolicDist)
| #RenderedDist(DistTypes.shape)
| #SymbolicDist(SymbolicDistTypes.symbolicDist)
| #RenderedDist(PointSetTypes.pointSetDist)
| #Function(array<string>, node)
]
@ -61,8 +61,8 @@ module Primative = {
module SamplingDistribution = {
type t = [
| #SymbolicDist(SymbolicTypes.symbolicDist)
| #RenderedDist(DistTypes.shape)
| #SymbolicDist(SymbolicDistTypes.symbolicDist)
| #RenderedDist(PointSetTypes.pointSetDist)
]
let isSamplingDistribution: node => bool = x =>
@ -98,7 +98,7 @@ module SamplingDistribution = {
)
let sampleN = n =>
map(~renderedDistFn=Shape.sampleNRendered(n), ~symbolicDistFn=SymbolicDist.T.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)) {
@ -126,12 +126,13 @@ module SamplingDistribution = {
)
// todo: This bottom part should probably be somewhere else.
let shape =
// todo: REFACTOR: I'm not sure about the SampleSet line.
let pointSetDist =
samples
|> E.O.fmap(SamplesToShape.fromSamples(~samplingInputs=evaluationParams.samplingInputs))
|> E.O.bind(_, r => r.shape)
|> E.O.fmap(r => SampleSet.toPointSetDist(~samplingInputs=evaluationParams.samplingInputs, ~samples=r, ()))
|> E.O.bind(_, r => r.pointSetDist)
|> E.O.toResult("No response")
shape |> E.R.fmap(r => #Normalize(#RenderedDist(r)))
pointSetDist |> E.R.fmap(r => #Normalize(#RenderedDist(r)))
})
}
}

View File

@ -84,13 +84,13 @@ let makeDist = (name, fn) =>
)
let floatFromDist = (
distToFloatOp: ExpressionTypes.distToFloatOperation,
distToFloatOp: ASTTypes.distToFloatOperation,
t: TypeSystem.samplingDist,
): result<node, string> =>
switch t {
| #SymbolicDist(s) =>
SymbolicDist.T.operate(distToFloatOp, s) |> E.R.bind(_, v => Ok(#SymbolicDist(#Float(v))))
| #RenderedDist(rs) => Shape.operate(distToFloatOp, rs) |> (v => Ok(#SymbolicDist(#Float(v))))
| #RenderedDist(rs) => PointSetDist.operate(distToFloatOp, rs) |> (v => Ok(#SymbolicDist(#Float(v))))
}
let verticalScaling = (scaleOp, rs, scaleBy) => {
@ -100,7 +100,7 @@ let verticalScaling = (scaleOp, rs, scaleBy) => {
let integralCacheFn = Operation.Scale.toIntegralCacheFn(scaleOp)
Ok(
#RenderedDist(
Shape.T.mapY(
PointSetDist.T.mapY(
~integralSumCacheFn=integralSumCacheFn(scaleBy),
~integralCacheFn=integralCacheFn(scaleBy),
~fn=fn(scaleBy),
@ -111,7 +111,7 @@ let verticalScaling = (scaleOp, rs, scaleBy) => {
}
module Multimodal = {
let getByNameResult = ExpressionTypes.ExpressionTree.Hash.getByNameResult
let getByNameResult = ASTTypes.AST.Hash.getByNameResult
let _paramsToDistsAndWeights = (r: array<typedValue>) =>
switch r {
@ -209,7 +209,7 @@ let all = [
~run=x =>
switch x {
| [#SamplingDist(#SymbolicDist(c))] => Ok(#SymbolicDist(c))
| [#SamplingDist(#RenderedDist(c))] => Ok(#RenderedDist(Shape.T.normalize(c)))
| [#SamplingDist(#RenderedDist(c))] => Ok(#RenderedDist(PointSetDist.T.normalize(c)))
| e => wrongInputsError(e)
},
(),

View File

@ -1,9 +1,9 @@
type node = ExpressionTypes.ExpressionTree.node
let getFloat = ExpressionTypes.ExpressionTree.getFloat
type node = ASTTypes.AST.node
let getFloat = ASTTypes.AST.getFloat
type samplingDist = [
| #SymbolicDist(SymbolicTypes.symbolicDist)
| #RenderedDist(DistTypes.shape)
| #SymbolicDist(SymbolicDistTypes.symbolicDist)
| #RenderedDist(PointSetTypes.pointSetDist)
]
type rec hashType = array<(string, _type)>
@ -18,7 +18,7 @@ and _type = [
type rec hashTypedValue = array<(string, typedValue)>
and typedValue = [
| #Float(float)
| #RenderedDist(DistTypes.shape)
| #RenderedDist(PointSetTypes.pointSetDist)
| #SamplingDist(samplingDist)
| #Array(array<typedValue>)
| #Hash(hashTypedValue)
@ -39,7 +39,7 @@ module TypedValue = {
let rec toString: typedValue => string = x =>
switch x {
| #SamplingDist(_) => "[sampling dist]"
| #RenderedDist(_) => "[rendered Shape]"
| #RenderedDist(_) => "[rendered PointSetDist]"
| #Float(f) => "Float: " ++ Js.Float.toString(f)
| #Array(a) => "[" ++ ((a |> E.A.fmap(toString) |> Js.String.concatMany(_, ",")) ++ "]")
| #Hash(v) =>
@ -61,7 +61,7 @@ module TypedValue = {
|> 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: " ++ ExpressionTreeBasic.toString(e))
| e => Error("Wrong type: " ++ ASTBasic.toString(e))
}
// todo: Arrays and hashes
@ -78,7 +78,7 @@ module TypedValue = {
node,
) |> E.R.bind(_, fromNode)
| (#RenderedDistribution, _) =>
ExpressionTypes.ExpressionTree.Render.render(evaluationParams, node) |> E.R.bind(_, fromNode)
ASTTypes.AST.Render.render(evaluationParams, node) |> E.R.bind(_, fromNode)
| (#Array(_type), #Array(b)) =>
b
|> E.A.fmap(fromNodeWithTypeCoercion(evaluationParams, _type))
@ -89,7 +89,7 @@ module TypedValue = {
named |> E.A.fmap(((name, intendedType)) => (
name,
intendedType,
ExpressionTypes.ExpressionTree.Hash.getByName(r, name),
ASTTypes.AST.Hash.getByName(r, name),
))
let typedHash =
keyValues
@ -172,7 +172,7 @@ module Function = {
|> E.A.R.firstErrorOrOpen
let inputsToTypedValues = (
evaluationParams: ExpressionTypes.ExpressionTree.evaluationParams,
evaluationParams: ASTTypes.AST.evaluationParams,
inputNodes: inputNodes,
t: t,
) =>
@ -181,7 +181,7 @@ module Function = {
)
let run = (
evaluationParams: ExpressionTypes.ExpressionTree.evaluationParams,
evaluationParams: ASTTypes.AST.evaluationParams,
inputNodes: inputNodes,
t: t,
) =>

View File

@ -122,7 +122,7 @@ module MathAdtToDistDst = {
| _ => Error("Lognormal distribution needs either mean and stdev or mu and sigma")
}
| _ =>
parseArgs() |> E.R.fmap((args: array<ExpressionTypes.ExpressionTree.node>) =>
parseArgs() |> E.R.fmap((args: array<ASTTypes.AST.node>) =>
#FunctionCall("lognormal", args)
)
}
@ -130,8 +130,8 @@ module MathAdtToDistDst = {
// Error("Dotwise exponentiation needs two operands")
let operationParser = (
name: string,
args: result<array<ExpressionTypes.ExpressionTree.node>, string>,
): result<ExpressionTypes.ExpressionTree.node, string> => {
args: result<array<ASTTypes.AST.node>, string>,
): result<ASTTypes.AST.node, string> => {
let toOkAlgebraic = r => Ok(#AlgebraicCombination(r))
let toOkPointwise = r => Ok(#PointwiseCombination(r))
let toOkTruncate = r => Ok(#Truncate(r))
@ -170,12 +170,12 @@ module MathAdtToDistDst = {
let functionParser = (
nodeParser: MathJsonToMathJsAdt.arg => Belt.Result.t<
ExpressionTypes.ExpressionTree.node,
ASTTypes.AST.node,
string,
>,
name: string,
args: array<MathJsonToMathJsAdt.arg>,
): result<ExpressionTypes.ExpressionTree.node, string> => {
): result<ASTTypes.AST.node, string> => {
let parseArray = ags => ags |> E.A.fmap(nodeParser) |> E.A.R.firstErrorOrOpen
let parseArgs = () => parseArray(args)
switch name {
@ -212,27 +212,27 @@ module MathAdtToDistDst = {
| (Some(Error(r)), _) => Error(r)
| (_, Error(r)) => Error(r)
| (None, Ok(dists)) =>
let hash: ExpressionTypes.ExpressionTree.node = #FunctionCall(
let hash: ASTTypes.AST.node = #FunctionCall(
"multimodal",
[#Hash([("dists", #Array(dists)), ("weights", #Array([]))])],
)
Ok(hash)
| (Some(Ok(weights)), Ok(dists)) =>
let hash: ExpressionTypes.ExpressionTree.node = #FunctionCall(
let hash: ASTTypes.AST.node = #FunctionCall(
"multimodal",
[#Hash([("dists", #Array(dists)), ("weights", #Array(weights))])],
)
Ok(hash)
}
| name =>
parseArgs() |> E.R.fmap((args: array<ExpressionTypes.ExpressionTree.node>) =>
parseArgs() |> E.R.fmap((args: array<ASTTypes.AST.node>) =>
#FunctionCall(name, args)
)
}
}
let rec nodeParser: MathJsonToMathJsAdt.arg => result<
ExpressionTypes.ExpressionTree.node,
ASTTypes.AST.node,
string,
> = x =>
switch x {
@ -246,7 +246,7 @@ module MathAdtToDistDst = {
// let evaluatedExpression = run(expression);
// `Function(_ => Ok(evaluatedExpression));
// }
let rec topLevel = (r): result<ExpressionTypes.Program.program, string> =>
let rec topLevel = (r): result<ASTTypes.Program.program, string> =>
switch r {
| FunctionAssignment({name, args, expression}) =>
switch nodeParser(expression) {
@ -267,7 +267,7 @@ module MathAdtToDistDst = {
blocks |> E.A.fmap(b => topLevel(b)) |> E.A.R.firstErrorOrOpen |> E.R.fmap(E.A.concatMany)
}
let run = (r): result<ExpressionTypes.Program.program, string> =>
let run = (r): result<ASTTypes.Program.program, string> =>
r |> MathAdtCleaner.run |> topLevel
}

View File

@ -96,10 +96,10 @@ let toDiscretePointMassesFromTriangulars = (
}
let combineShapesContinuousContinuous = (
op: ExpressionTypes.algebraicOperation,
s1: DistTypes.xyShape,
s2: DistTypes.xyShape,
): DistTypes.xyShape => {
op: ASTTypes.algebraicOperation,
s1: PointSetTypes.xyShape,
s2: PointSetTypes.xyShape,
): PointSetTypes.xyShape => {
let t1n = s1 |> XYShape.T.length
let t2n = s2 |> XYShape.T.length
@ -188,7 +188,7 @@ let combineShapesContinuousContinuous = (
{xs: outputXs, ys: outputYs}
}
let toDiscretePointMassesFromDiscrete = (s: DistTypes.xyShape): pointMassesWithMoments => {
let toDiscretePointMassesFromDiscrete = (s: PointSetTypes.xyShape): pointMassesWithMoments => {
let {xs, ys}: XYShape.T.t = s
let n = E.A.length(xs)
@ -200,10 +200,10 @@ let toDiscretePointMassesFromDiscrete = (s: DistTypes.xyShape): pointMassesWithM
}
let combineShapesContinuousDiscrete = (
op: ExpressionTypes.algebraicOperation,
continuousShape: DistTypes.xyShape,
discreteShape: DistTypes.xyShape,
): DistTypes.xyShape => {
op: ASTTypes.algebraicOperation,
continuousShape: PointSetTypes.xyShape,
discreteShape: PointSetTypes.xyShape,
): PointSetTypes.xyShape => {
let t1n = continuousShape |> XYShape.T.length
let t2n = discreteShape |> XYShape.T.length

View File

@ -1,6 +1,6 @@
open Distributions
type t = DistTypes.continuousShape
type t = PointSetTypes.continuousShape
let getShape = (t: t) => t.xyShape
let interpolation = (t: t) => t.interpolation
let make = (~interpolation=#Linear, ~integralSumCache=None, ~integralCache=None, xyShape): t => {
@ -17,10 +17,10 @@ let shapeMap = (fn, {xyShape, interpolation, integralSumCache, integralCache}: t
}
let lastY = (t: t) => t |> getShape |> XYShape.T.lastY
let oShapeMap = (fn, {xyShape, interpolation, integralSumCache, integralCache}: t): option<
DistTypes.continuousShape,
PointSetTypes.continuousShape,
> => fn(xyShape) |> E.O.fmap(make(~interpolation, ~integralSumCache, ~integralCache))
let emptyIntegral: DistTypes.continuousShape = {
let emptyIntegral: PointSetTypes.continuousShape = {
xyShape: {
xs: [neg_infinity],
ys: [0.0],
@ -29,7 +29,7 @@ let emptyIntegral: DistTypes.continuousShape = {
integralSumCache: Some(0.0),
integralCache: None,
}
let empty: DistTypes.continuousShape = {
let empty: PointSetTypes.continuousShape = {
xyShape: XYShape.T.empty,
interpolation: #Linear,
integralSumCache: Some(0.0),
@ -47,11 +47,11 @@ let stepwiseToLinear = (t: t): t =>
let combinePointwise = (
~integralSumCachesFn=(_, _) => None,
~integralCachesFn: (t, t) => option<t>=(_, _) => None,
~distributionType: DistTypes.distributionType=#PDF,
~distributionType: PointSetTypes.distributionType=#PDF,
fn: (float, float) => float,
t1: DistTypes.continuousShape,
t2: DistTypes.continuousShape,
): DistTypes.continuousShape => {
t1: PointSetTypes.continuousShape,
t2: PointSetTypes.continuousShape,
): PointSetTypes.continuousShape => {
// If we're adding the distributions, and we know the total of each, then we
// can just sum them up. Otherwise, all bets are off.
let combinedIntegralSum = Common.combineIntegralSums(
@ -130,19 +130,19 @@ let rec scaleBy = (~scale=1.0, t: t): t => {
}
module T = Dist({
type t = DistTypes.continuousShape
type integral = DistTypes.continuousShape
type t = PointSetTypes.continuousShape
type integral = PointSetTypes.continuousShape
let minX = shapeFn(XYShape.T.minX)
let maxX = shapeFn(XYShape.T.maxX)
let mapY = mapY
let updateIntegralCache = updateIntegralCache
let toDiscreteProbabilityMassFraction = _ => 0.0
let toShape = (t: t): DistTypes.shape => Continuous(t)
let toPointSetDist = (t: t): PointSetTypes.pointSetDist => Continuous(t)
let xToY = (f, {interpolation, xyShape}: t) =>
switch interpolation {
| #Stepwise => xyShape |> XYShape.XtoY.stepwiseIncremental(f) |> E.O.default(0.0)
| #Linear => xyShape |> XYShape.XtoY.linear(f)
} |> DistTypes.MixedPoint.makeContinuous
} |> PointSetTypes.MixedPoint.makeContinuous
let truncate = (leftCutoff: option<float>, rightCutoff: option<float>, t: t) => {
let lc = E.O.default(neg_infinity, leftCutoff)
@ -211,9 +211,9 @@ module T = Dist({
/* This simply creates multiple copies of the continuous distribution, scaled and shifted according to
each discrete data point, and then adds them all together. */
let combineAlgebraicallyWithDiscrete = (
op: ExpressionTypes.algebraicOperation,
op: ASTTypes.algebraicOperation,
t1: t,
t2: DistTypes.discreteShape,
t2: PointSetTypes.discreteShape,
) => {
let t1s = t1 |> getShape
let t2s = t2.xyShape // TODO would like to use Discrete.getShape here, but current file structure doesn't allow for that
@ -244,7 +244,7 @@ let combineAlgebraicallyWithDiscrete = (
}
}
let combineAlgebraically = (op: ExpressionTypes.algebraicOperation, t1: t, t2: t) => {
let combineAlgebraically = (op: ASTTypes.algebraicOperation, t1: t, t2: t) => {
let s1 = t1 |> getShape
let s2 = t2 |> getShape
let t1n = s1 |> XYShape.T.length

View File

@ -1,6 +1,6 @@
open Distributions
type t = DistTypes.discreteShape
type t = PointSetTypes.discreteShape
let make = (~integralSumCache=None, ~integralCache=None, xyShape): t => {
xyShape: xyShape,
@ -16,13 +16,13 @@ let getShape = (t: t) => t.xyShape
let oShapeMap = (fn, {xyShape, integralSumCache, integralCache}: t): option<t> =>
fn(xyShape) |> E.O.fmap(make(~integralSumCache, ~integralCache))
let emptyIntegral: DistTypes.continuousShape = {
let emptyIntegral: PointSetTypes.continuousShape = {
xyShape: {xs: [neg_infinity], ys: [0.0]},
interpolation: #Stepwise,
integralSumCache: Some(0.0),
integralCache: None,
}
let empty: DistTypes.discreteShape = {
let empty: PointSetTypes.discreteShape = {
xyShape: XYShape.T.empty,
integralSumCache: Some(0.0),
integralCache: Some(emptyIntegral),
@ -35,13 +35,13 @@ let lastY = (t: t) => t |> getShape |> XYShape.T.lastY
let combinePointwise = (
~integralSumCachesFn=(_, _) => None,
~integralCachesFn: (
DistTypes.continuousShape,
DistTypes.continuousShape,
) => option<DistTypes.continuousShape>=(_, _) => None,
PointSetTypes.continuousShape,
PointSetTypes.continuousShape,
) => option<PointSetTypes.continuousShape>=(_, _) => None,
fn,
t1: DistTypes.discreteShape,
t2: DistTypes.discreteShape,
): DistTypes.discreteShape => {
t1: PointSetTypes.discreteShape,
t2: PointSetTypes.discreteShape,
): PointSetTypes.discreteShape => {
let combinedIntegralSum = Common.combineIntegralSums(
integralSumCachesFn,
t1.integralSumCache,
@ -67,7 +67,7 @@ let reduce = (
~integralCachesFn=(_, _) => None,
fn,
discreteShapes,
): DistTypes.discreteShape =>
): PointSetTypes.discreteShape =>
discreteShapes |> E.A.fold_left(
combinePointwise(~integralSumCachesFn, ~integralCachesFn, fn),
empty,
@ -85,7 +85,7 @@ let updateIntegralCache = (integralCache, t: t): t => {
/* This multiples all of the data points together and creates a new discrete distribution from the results.
Data points at the same xs get added together. It may be a good idea to downsample t1 and t2 before and/or the result after. */
let combineAlgebraically = (op: ExpressionTypes.algebraicOperation, t1: t, t2: t): t => {
let combineAlgebraically = (op: ASTTypes.algebraicOperation, t1: t, t2: t): t => {
let t1s = t1 |> getShape
let t2s = t2 |> getShape
let t1n = t1s |> XYShape.T.length
@ -134,8 +134,8 @@ let scaleBy = (~scale=1.0, t: t): t => {
}
module T = Dist({
type t = DistTypes.discreteShape
type integral = DistTypes.continuousShape
type t = PointSetTypes.discreteShape
type integral = PointSetTypes.continuousShape
let integral = t =>
switch (getShape(t) |> XYShape.T.isEmpty, t.integralCache) {
| (true, _) => emptyIntegral
@ -157,7 +157,7 @@ module T = Dist({
let toDiscreteProbabilityMassFraction = _ => 1.0
let mapY = mapY
let updateIntegralCache = updateIntegralCache
let toShape = (t: t): DistTypes.shape => Discrete(t)
let toPointSetDist = (t: t): PointSetTypes.pointSetDist => Discrete(t)
let toContinuous = _ => None
let toDiscrete = t => Some(t)
@ -199,7 +199,7 @@ module T = Dist({
|> getShape
|> XYShape.XtoY.stepwiseIfAtX(f)
|> E.O.default(0.0)
|> DistTypes.MixedPoint.makeDiscrete
|> PointSetTypes.MixedPoint.makeDiscrete
let integralXtoY = (f, t) => t |> integral |> Continuous.getShape |> XYShape.XtoY.linear(f)

View File

@ -1,40 +1,40 @@
open DistTypes;
open PointSetTypes;
type t = DistTypes.distPlus;
type t = PointSetTypes.distPlus;
let shapeIntegral = shape => Shape.T.Integral.get(shape);
let pointSetDistIntegral = pointSetDist => PointSetDist.T.Integral.get(pointSetDist);
let make =
(
~shape,
~pointSetDist,
~squiggleString,
~domain=Complete,
~unit=UnspecifiedDistribution,
(),
)
: t => {
let integral = shapeIntegral(shape);
{shape, domain, integralCache: integral, unit, squiggleString};
let integral = pointSetDistIntegral(pointSetDist);
{pointSetDist, domain, integralCache: integral, unit, squiggleString};
};
let update =
(
~shape=?,
~pointSetDist=?,
~integralCache=?,
~domain=?,
~unit=?,
~squiggleString=?,
t: t,
) => {
shape: E.O.default(t.shape, shape),
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),
};
let updateShape = (shape, t) => {
let integralCache = shapeIntegral(shape);
update(~shape, ~integralCache, t);
let updateShape = (pointSetDist, t) => {
let integralCache = pointSetDistIntegral(pointSetDist);
update(~pointSetDist, ~integralCache, t);
};
let domainIncludedProbabilityMass = (t: t) =>
@ -43,87 +43,87 @@ let domainIncludedProbabilityMass = (t: t) =>
let domainIncludedProbabilityMassAdjustment = (t: t, f) =>
f *. Domain.includedProbabilityMass(t.domain);
let toShape = ({shape, _}: t) => shape;
let toPointSetDist = ({pointSetDist, _}: t) => pointSetDist;
let shapeFn = (fn, {shape}: t) => fn(shape);
let pointSetDistFn = (fn, {pointSetDist}: t) => fn(pointSetDist);
module T =
Distributions.Dist({
type t = DistTypes.distPlus;
type integral = DistTypes.distPlus;
let toShape = toShape;
let toContinuous = shapeFn(Shape.T.toContinuous);
let toDiscrete = shapeFn(Shape.T.toDiscrete);
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 |> toShape |> Shape.T.normalize;
let normalizedShape = t |> toPointSetDist |> PointSetDist.T.normalize;
t |> updateShape(normalizedShape);
};
let truncate = (leftCutoff, rightCutoff, t: t): t => {
let truncatedShape =
t
|> toShape
|> Shape.T.truncate(leftCutoff, rightCutoff);
|> toPointSetDist
|> PointSetDist.T.truncate(leftCutoff, rightCutoff);
t |> updateShape(truncatedShape);
};
let xToY = (f, t: t) =>
t
|> toShape
|> Shape.T.xToY(f)
|> toPointSetDist
|> PointSetDist.T.xToY(f)
|> MixedPoint.fmap(domainIncludedProbabilityMassAdjustment(t));
let minX = shapeFn(Shape.T.minX);
let maxX = shapeFn(Shape.T.maxX);
let minX = pointSetDistFn(PointSetDist.T.minX);
let maxX = pointSetDistFn(PointSetDist.T.maxX);
let toDiscreteProbabilityMassFraction =
shapeFn(Shape.T.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<DistTypes.continuousShape>, t) =>
let updateIntegralCache = (integralCache: option<PointSetTypes.continuousShape>, t) =>
update(~integralCache=E.O.default(t.integralCache, integralCache), t);
let downsample = (i, t): t =>
updateShape(t |> toShape |> Shape.T.downsample(i), t);
updateShape(t |> toPointSetDist |> PointSetDist.T.downsample(i), t);
// todo: adjust for limit, maybe?
let mapY =
(
~integralSumCacheFn=previousIntegralSum => None,
~integralCacheFn=previousIntegralCache => None,
~fn,
{shape, _} as t: t,
{pointSetDist, _} as t: t,
)
: t =>
Shape.T.mapY(~integralSumCacheFn, ~fn, shape)
PointSetDist.T.mapY(~integralSumCacheFn, ~fn, pointSetDist)
|> updateShape(_, t);
// get the total of everything
let integralEndY = (t: t) => {
Shape.T.Integral.sum(
toShape(t),
PointSetDist.T.Integral.sum(
toPointSetDist(t),
);
};
// TODO: Fix this below, obviously. Adjust for limits
let integralXtoY = (f, t: t) => {
Shape.T.Integral.xToY(
PointSetDist.T.Integral.xToY(
f,
toShape(t),
toPointSetDist(t),
)
|> domainIncludedProbabilityMassAdjustment(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) => {
Shape.T.Integral.yToX(f, toShape(t));
PointSetDist.T.Integral.yToX(f, toPointSetDist(t));
};
let mean = (t: t) => {
Shape.T.mean(t.shape);
PointSetDist.T.mean(t.pointSetDist);
};
let variance = (t: t) => Shape.T.variance(t.shape);
let variance = (t: t) => PointSetDist.T.variance(t.pointSetDist);
});

View File

@ -5,20 +5,20 @@ module type dist = {
let maxX: t => float
let mapY: (
~integralSumCacheFn: float => option<float>=?,
~integralCacheFn: DistTypes.continuousShape => option<DistTypes.continuousShape>=?,
~integralCacheFn: PointSetTypes.continuousShape => option<PointSetTypes.continuousShape>=?,
~fn: float => float,
t,
) => t
let xToY: (float, t) => DistTypes.mixedPoint
let toShape: t => DistTypes.shape
let toContinuous: t => option<DistTypes.continuousShape>
let toDiscrete: t => option<DistTypes.discreteShape>
let xToY: (float, t) => PointSetTypes.mixedPoint
let toPointSetDist: t => PointSetTypes.pointSetDist
let toContinuous: t => option<PointSetTypes.continuousShape>
let toDiscrete: t => option<PointSetTypes.discreteShape>
let normalize: t => t
let toDiscreteProbabilityMassFraction: t => float
let downsample: (int, t) => t
let truncate: (option<float>, option<float>, t) => t
let updateIntegralCache: (option<DistTypes.continuousShape>, t) => t
let updateIntegralCache: (option<PointSetTypes.continuousShape>, t) => t
let integral: t => integral
let integralEndY: t => float
@ -39,7 +39,7 @@ module Dist = (T: dist) => {
let mapY = T.mapY
let xToY = T.xToY
let downsample = T.downsample
let toShape = T.toShape
let toPointSetDist = T.toPointSetDist
let toDiscreteProbabilityMassFraction = T.toDiscreteProbabilityMassFraction
let toContinuous = T.toContinuous
let toDiscrete = T.toDiscrete
@ -74,11 +74,11 @@ module Common = {
let combineIntegrals = (
combineFn: (
DistTypes.continuousShape,
DistTypes.continuousShape,
) => option<DistTypes.continuousShape>,
t1IntegralCache: option<DistTypes.continuousShape>,
t2IntegralCache: option<DistTypes.continuousShape>,
PointSetTypes.continuousShape,
PointSetTypes.continuousShape,
) => option<PointSetTypes.continuousShape>,
t1IntegralCache: option<PointSetTypes.continuousShape>,
t2IntegralCache: option<PointSetTypes.continuousShape>,
) =>
switch (t1IntegralCache, t2IntegralCache) {
| (None, _)

View File

@ -1,6 +1,6 @@
open Distributions
type t = DistTypes.mixedShape
type t = PointSetTypes.mixedShape
let make = (~integralSumCache=None, ~integralCache=None, ~continuous, ~discrete): t => {
continuous: continuous,
discrete: discrete,
@ -37,13 +37,13 @@ let updateIntegralCache = (integralCache, t: t): t => {
}
module T = Dist({
type t = DistTypes.mixedShape
type integral = DistTypes.continuousShape
type t = PointSetTypes.mixedShape
type integral = PointSetTypes.continuousShape
let minX = ({continuous, discrete}: t) =>
min(Continuous.T.minX(continuous), Discrete.T.minX(discrete))
let maxX = ({continuous, discrete}: t) =>
max(Continuous.T.maxX(continuous), Discrete.T.maxX(discrete))
let toShape = (t: t): DistTypes.shape => Mixed(t)
let toPointSetDist = (t: t): PointSetTypes.pointSetDist => Mixed(t)
let updateIntegralCache = updateIntegralCache
@ -103,7 +103,7 @@ module T = Dist({
let {continuous, discrete}: t = normalize(t)
let c = Continuous.T.xToY(x, continuous)
let d = Discrete.T.xToY(x, discrete)
DistTypes.MixedPoint.add(c, d) // "add" here just combines the two values into a single MixedPoint.
PointSetTypes.MixedPoint.add(c, d) // "add" here just combines the two values into a single MixedPoint.
}
let toDiscreteProbabilityMassFraction = ({discrete, continuous}: t) => {
@ -170,13 +170,13 @@ module T = Dist({
~fn,
t: t,
): t => {
let yMappedDiscrete: DistTypes.discreteShape =
let yMappedDiscrete: PointSetTypes.discreteShape =
t.discrete
|> Discrete.T.mapY(~fn)
|> Discrete.updateIntegralSumCache(E.O.bind(t.discrete.integralSumCache, integralSumCacheFn))
|> Discrete.updateIntegralCache(E.O.bind(t.discrete.integralCache, integralCacheFn))
let yMappedContinuous: DistTypes.continuousShape =
let yMappedContinuous: PointSetTypes.continuousShape =
t.continuous
|> Continuous.T.mapY(~fn)
|> Continuous.updateIntegralSumCache(
@ -227,7 +227,7 @@ module T = Dist({
}
})
let combineAlgebraically = (op: ExpressionTypes.algebraicOperation, t1: t, t2: t): t => {
let combineAlgebraically = (op: ASTTypes.algebraicOperation, t1: t, t2: t): t => {
// Discrete convolution can cause a huge increase in the number of samples,
// so we'll first downsample.

View File

@ -9,9 +9,9 @@ type assumptions = {
}
let buildSimple = (
~continuous: option<DistTypes.continuousShape>,
~discrete: option<DistTypes.discreteShape>,
): option<DistTypes.shape> => {
~continuous: option<PointSetTypes.continuousShape>,
~discrete: option<PointSetTypes.discreteShape>,
): option<PointSetTypes.pointSetDist> => {
let continuous =
continuous |> E.O.default(Continuous.make(~integralSumCache=Some(0.0), {xs: [], ys: []}))
let discrete =

View File

@ -1,6 +1,6 @@
open Distributions
type t = DistTypes.shape
type t = PointSetTypes.pointSetDist
let mapToAll = ((fn1, fn2, fn3), t: t) =>
switch t {
| Mixed(m) => fn1(m)
@ -33,49 +33,49 @@ let toMixed = mapToAll((
),
))
let combineAlgebraically = (op: ExpressionTypes.algebraicOperation, t1: t, t2: t): t =>
let combineAlgebraically = (op: ASTTypes.algebraicOperation, t1: t, t2: t): t =>
switch (t1, t2) {
| (Continuous(m1), Continuous(m2)) =>
Continuous.combineAlgebraically(op, m1, m2) |> Continuous.T.toShape
Continuous.combineAlgebraically(op, m1, m2) |> Continuous.T.toPointSetDist
| (Continuous(m1), Discrete(m2))
| (Discrete(m2), Continuous(m1)) =>
Continuous.combineAlgebraicallyWithDiscrete(op, m1, m2) |> Continuous.T.toShape
| (Discrete(m1), Discrete(m2)) => Discrete.combineAlgebraically(op, m1, m2) |> Discrete.T.toShape
| (m1, m2) => Mixed.combineAlgebraically(op, toMixed(m1), toMixed(m2)) |> Mixed.T.toShape
Continuous.combineAlgebraicallyWithDiscrete(op, m1, m2) |> Continuous.T.toPointSetDist
| (Discrete(m1), Discrete(m2)) => Discrete.combineAlgebraically(op, m1, m2) |> Discrete.T.toPointSetDist
| (m1, m2) => Mixed.combineAlgebraically(op, toMixed(m1), toMixed(m2)) |> Mixed.T.toPointSetDist
}
let combinePointwise = (
~integralSumCachesFn: (float, float) => option<float>=(_, _) => None,
~integralCachesFn: (
DistTypes.continuousShape,
DistTypes.continuousShape,
) => option<DistTypes.continuousShape>=(_, _) => None,
PointSetTypes.continuousShape,
PointSetTypes.continuousShape,
) => option<PointSetTypes.continuousShape>=(_, _) => None,
fn,
t1: t,
t2: t,
) =>
switch (t1, t2) {
| (Continuous(m1), Continuous(m2)) =>
DistTypes.Continuous(
PointSetTypes.Continuous(
Continuous.combinePointwise(~integralSumCachesFn, ~integralCachesFn, fn, m1, m2),
)
| (Discrete(m1), Discrete(m2)) =>
DistTypes.Discrete(
PointSetTypes.Discrete(
Discrete.combinePointwise(~integralSumCachesFn, ~integralCachesFn, fn, m1, m2),
)
| (m1, m2) =>
DistTypes.Mixed(
PointSetTypes.Mixed(
Mixed.combinePointwise(~integralSumCachesFn, ~integralCachesFn, fn, toMixed(m1), toMixed(m2)),
)
}
module T = Dist({
type t = DistTypes.shape
type integral = DistTypes.continuousShape
type t = PointSetTypes.pointSetDist
type integral = PointSetTypes.continuousShape
let xToY = (f: float) => mapToAll((Mixed.T.xToY(f), Discrete.T.xToY(f), Continuous.T.xToY(f)))
let toShape = (t: t) => t
let toPointSetDist = (t: t) => t
let toContinuous = t => None
let toDiscrete = t => None
@ -163,7 +163,7 @@ module T = Dist({
})
let pdf = (f: float, t: t) => {
let mixedPoint: DistTypes.mixedPoint = T.xToY(f, t)
let mixedPoint: PointSetTypes.mixedPoint = T.xToY(f, t)
mixedPoint.continuous +. mixedPoint.discrete
}
@ -197,7 +197,7 @@ let sampleNRendered = (n, dist) => {
doN(n, () => sample(distWithUpdatedIntegralCache))
}
let operate = (distToFloatOp: ExpressionTypes.distToFloatOperation, s): float =>
let operate = (distToFloatOp: ASTTypes.distToFloatOperation, s): float =>
switch distToFloatOp {
| #Pdf(f) => pdf(f, s)
| #Cdf(f) => pdf(f, s)

View File

@ -50,15 +50,15 @@ type mixedShape = {
integralCache: option<continuousShape>,
}
type shapeMonad<'a, 'b, 'c> =
type pointSetDistMonad<'a, 'b, 'c> =
| Mixed('a)
| Discrete('b)
| Continuous('c)
type shape = shapeMonad<mixedShape, discreteShape, continuousShape>
type pointSetDist = pointSetDistMonad<mixedShape, discreteShape, continuousShape>
module ShapeMonad = {
let fmap = (t: shapeMonad<'a, 'b, 'c>, (fn1, fn2, fn3)): shapeMonad<'d, 'e, 'f> =>
let fmap = (t: pointSetDistMonad<'a, 'b, 'c>, (fn1, fn2, fn3)): pointSetDistMonad<'d, 'e, 'f> =>
switch t {
| Mixed(m) => Mixed(fn1(m))
| Discrete(m) => Discrete(fn2(m))
@ -68,13 +68,13 @@ module ShapeMonad = {
type generationSource =
| SquiggleString(string)
| Shape(shape)
| Shape(pointSetDist)
type distributionUnit =
| UnspecifiedDistribution
type distPlus = {
shape: shape,
pointSetDist: pointSetDist,
domain: domain,
integralCache: continuousShape,
unit: distributionUnit,

View File

@ -1,4 +1,4 @@
open DistTypes
open PointSetTypes
let interpolate = (xMin: float, xMax: float, yMin: float, yMax: float, xIntended: float): float => {
let minProportion = (xMax -. xIntended) /. (xMax -. xMin)
@ -126,8 +126,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: DistTypes.interpolationStrategy,
extrapolation: DistTypes.extrapolationStrategy,
interpolation: PointSetTypes.interpolationStrategy,
extrapolation: PointSetTypes.extrapolationStrategy,
): interpolator =>
switch (interpolation, extrapolation) {
| (#Linear, #UseZero) =>
@ -395,7 +395,7 @@ module Analysis = {
let integrateContinuousShape = (
~indefiniteIntegralStepwise=(p, h1) => h1 *. p,
~indefiniteIntegralLinear=(p, a, b) => a *. p +. b *. p ** 2.0 /. 2.0,
t: DistTypes.continuousShape,
t: PointSetTypes.continuousShape,
): float => {
let xs = t.xyShape.xs
let ys = t.xyShape.ys
@ -424,7 +424,7 @@ module Analysis = {
})
}
let getMeanOfSquaresContinuousShape = (t: DistTypes.continuousShape) => {
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)

View File

@ -15,7 +15,6 @@ const samplesToContinuousPdf = (
return {xs: pdf.map(r => r.x), ys: pdf.map(r => r.y)};
};
module.exports = {
samplesToContinuousPdf,
};

View File

@ -11,7 +11,7 @@ module Internals = {
type outputs = {
continuousParseParams: option<samplingStats>,
shape: option<DistTypes.shape>,
pointSetDist: option<PointSetTypes.pointSetDist>,
}
}
@ -22,7 +22,7 @@ module Internals = {
ys: array<float>,
}
let jsToDist = (d: distJs): DistTypes.xyShape => {
let jsToDist = (d: distJs): PointSetTypes.xyShape => {
xs: xsGet(d),
ys: ysGet(d),
}
@ -78,15 +78,15 @@ module Internals = {
}
}
let toShape = (
let toPointSetDist = (
~samples: Internals.T.t,
~samplingInputs: ExpressionTypes.ExpressionTree.samplingInputs,
~samplingInputs: ASTTypes.AST.samplingInputs,
(),
) => {
Array.fast_sort(compare, samples)
let (continuousPart, discretePart) = E.A.Sorted.Floats.split(samples)
let length = samples |> E.A.length |> float_of_int
let discrete: DistTypes.discreteShape =
let discrete: PointSetTypes.discreteShape =
discretePart
|> E.FloatFloatMap.fmap(r => r /. length)
|> E.FloatFloatMap.toArray
@ -127,17 +127,15 @@ let toShape = (
}
: None
let shape = MixedShapeBuilder.buildSimple(
let pointSetDist = MixedShapeBuilder.buildSimple(
~continuous=pdf |> E.O.fmap(fst),
~discrete=Some(discrete),
)
let samplesParse: Internals.Types.outputs = {
continuousParseParams: pdf |> E.O.fmap(snd),
shape: shape,
pointSetDist: pointSetDist,
}
samplesParse
}
let fromSamples = (~samplingInputs, samples) => toShape(~samples, ~samplingInputs, ())

View File

@ -1,4 +1,4 @@
open SymbolicTypes
open SymbolicDistTypes
module Normal = {
type t = normal
@ -272,7 +272,7 @@ module T = {
| #Float(n) => Float.mean(n)
}
let operate = (distToFloatOp: ExpressionTypes.distToFloatOperation, s) =>
let operate = (distToFloatOp: ASTTypes.distToFloatOperation, s) =>
switch distToFloatOp {
| #Cdf(f) => Ok(cdf(f, s))
| #Pdf(f) => Ok(pdf(f, s))
@ -302,7 +302,7 @@ module T = {
let tryAnalyticalSimplification = (
d1: symbolicDist,
d2: symbolicDist,
op: ExpressionTypes.algebraicOperation,
op: ASTTypes.algebraicOperation,
): analyticalSimplificationResult =>
switch (d1, d2) {
| (#Float(v1), #Float(v2)) =>
@ -317,7 +317,7 @@ module T = {
| _ => #NoSolution
}
let toShape = (sampleCount, d: symbolicDist): DistTypes.shape =>
let toPointSetDist = (sampleCount, d: symbolicDist): PointSetTypes.pointSetDist =>
switch d {
| #Float(v) => Discrete(Discrete.make(~integralSumCache=Some(1.0), {xs: [v], ys: [1.0]}))
| _ =>