Separated XYSHape into separate file

This commit is contained in:
Ozzie Gooen 2020-02-22 12:51:25 +00:00
parent 0c0fe76e4e
commit da172bfa94
5 changed files with 187 additions and 188 deletions

View File

@ -26,11 +26,10 @@ let buildIds = entries => {
f.id = curPath ++ "/" ++ genId(f.title, curPath); f.id = curPath ++ "/" ++ genId(f.title, curPath);
HS.set(entriesByPath, f.id, FolderEntry(f)); HS.set(entriesByPath, f.id, FolderEntry(f));
f.children f.children
|> E.L.iter(e => |> E.L.iter(
switch (e) { fun
| CompEntry(c) => processEntry(c, f.id) | CompEntry(c) => processEntry(c, f.id)
| FolderEntry(f) => processFolder(f, f.id) | FolderEntry(f) => processFolder(f, f.id),
}
); );
} }
and processEntry = (c: compEntry, curPath) => { and processEntry = (c: compEntry, curPath) => {
@ -38,11 +37,10 @@ let buildIds = entries => {
HS.set(entriesByPath, c.id, CompEntry(c)); HS.set(entriesByPath, c.id, CompEntry(c));
}; };
entries entries
|> E.L.iter(e => |> E.L.iter(
switch (e) { fun
| CompEntry(c) => processEntry(c, "") | CompEntry(c) => processEntry(c, "")
| FolderEntry(f) => processFolder(f, "") | FolderEntry(f) => processFolder(f, ""),
}
); );
}; };

View File

@ -50,7 +50,7 @@ let make =
marginBottom=50 marginBottom=50
marginTop=0 marginTop=0
onHover onHover
continuous={continuous |> E.O.fmap(Shape.XYShape.toJs)} continuous={continuous |> E.O.fmap(XYShape.toJs)}
showDistributionLines showDistributionLines
showDistributionYAxis showDistributionYAxis
showVerticalLine showVerticalLine

View File

@ -14,26 +14,29 @@ let max = (f1: option(float), f2: option(float)) =>
| (None, None) => None | (None, None) => None
}; };
type yPoint = type mixedPoint = {
| Mixed({
continuous: float, continuous: float,
discrete: float, discrete: float,
})
| Continuous(float)
| Discrete(float);
module YPoint = {
type t = yPoint;
let toContinuousValue = (t: t) =>
switch (t) {
| Continuous(f) => f
| Mixed({continuous}) => continuous
| _ => 0.0
}; };
let makeContinuous = (f: float): t => Continuous(f);
let makeDiscrete = (f: float): t => Discrete(f); module MixedPoint = {
let makeMixed = (c: float, d: float): t => type t = mixedPoint;
Mixed({continuous: c, discrete: d}); let toContinuousValue = (t: t) => t.continuous;
let toDiscreteValue = (t: t) => t.discrete;
let makeContinuous = (continuous: float): t => {continuous, discrete: 0.0};
let makeDiscrete = (discrete: float): t => {continuous: 0.0, discrete};
let fmap = (fn, t: t) => {
continuous: fn(t.continuous),
discrete: fn(t.discrete),
};
let combine2 = (fn, c: t, d: t): t => {
continuous: fn(c.continuous, d.continuous),
discrete: fn(c.discrete, d.discrete),
};
let add = combine2((a, b) => a +. b);
}; };
module type dist = { module type dist = {
@ -41,7 +44,7 @@ module type dist = {
let minX: t => option(float); let minX: t => option(float);
let maxX: t => option(float); let maxX: t => option(float);
let pointwiseFmap: (float => float, t) => t; let pointwiseFmap: (float => float, t) => t;
let xToY: (float, t) => yPoint; let xToY: (float, t) => mixedPoint;
let shape: t => DistributionTypes.shape; let shape: t => DistributionTypes.shape;
type integral; type integral;
@ -71,31 +74,33 @@ module Continuous =
Dist({ Dist({
type t = DistributionTypes.continuousShape; type t = DistributionTypes.continuousShape;
type integral = DistributionTypes.continuousShape; type integral = DistributionTypes.continuousShape;
let make = (shape, interpolation): t => {shape, interpolation};
let fromShape = shape => make(shape, `Linear);
let shape = (t: t) => t.shape;
let shapeFn = (fn, t: t) => t |> shape |> fn;
let shape = (t: t) => t.shape; let shape = (t: t) => t.shape;
let integral = (~cache, t) => let integral = (~cache, t) =>
cache cache
|> E.O.default( |> E.O.default(
t t
|> shape |> shape
|> Shape.XYShape.Range.integrateWithTriangles |> XYShape.Range.integrateWithTriangles
|> E.O.toExt("") |> E.O.toExt("")
|> Shape.Continuous.fromShape, |> fromShape,
); );
// This seems wrong, we really want the ending bit, I'd assume // This seems wrong, we really want the ending bit, I'd assume
let integralSum = (~cache, t) => let integralSum = (~cache, t) =>
t |> integral(~cache) |> shape |> Shape.XYShape.ySum; t |> integral(~cache) |> shape |> XYShape.ySum;
let minX = (t: t) => t |> shape |> Shape.XYShape.minX; let minX = shapeFn(XYShape.minX);
let maxX = (t: t) => t |> shape |> Shape.XYShape.maxX; let maxX = shapeFn(XYShape.maxX);
let pointwiseFmap = (fn, t: t) => let pointwiseFmap = (fn, t: t) =>
t t |> shape |> XYShape.pointwiseMap(fn) |> fromShape;
|> shape
|> Shape.XYShape.pointwiseMap(fn)
|> Shape.Continuous.fromShape;
let shape = (t: t): DistributionTypes.shape => Continuous(t); let shape = (t: t): DistributionTypes.shape => Continuous(t);
let xToY = (f, t) => let xToY = (f, t) =>
Shape.Continuous.findY(f, t) |> YPoint.makeContinuous; shapeFn(CdfLibrary.Distribution.findY(f), t)
|> MixedPoint.makeContinuous;
let integralXtoY = (~cache, f, t) => let integralXtoY = (~cache, f, t) =>
t |> integral(~cache) |> Shape.Continuous.findY(f); t |> integral(~cache) |> shapeFn(CdfLibrary.Distribution.findY(f));
}); });
module Discrete = module Discrete =
@ -103,16 +108,17 @@ module Discrete =
type t = DistributionTypes.discreteShape; type t = DistributionTypes.discreteShape;
type integral = DistributionTypes.continuousShape; type integral = DistributionTypes.continuousShape;
let integral = (~cache, t) => let integral = (~cache, t) =>
cache |> E.O.default(t |> Shape.Discrete.integrate); cache
let integralSum = (~cache, t) => t |> Shape.XYShape.ySum; |> E.O.default(t |> XYShape.accumulateYs |> Shape.Continuous.fromShape);
let minX = Shape.XYShape.minX; let integralSum = (~cache, t) => t |> XYShape.ySum;
let maxX = Shape.XYShape.maxX; let minX = XYShape.minX;
let pointwiseFmap = Shape.XYShape.pointwiseMap; let maxX = XYShape.maxX;
let pointwiseFmap = XYShape.pointwiseMap;
let shape = (t: t): DistributionTypes.shape => Discrete(t); let shape = (t: t): DistributionTypes.shape => Discrete(t);
let xToY = (f, t) => let xToY = (f, t) =>
CdfLibrary.Distribution.findY(f, t) |> (e => Discrete(e)); CdfLibrary.Distribution.findY(f, t) |> MixedPoint.makeDiscrete;
let integralXtoY = (~cache, f, t) => let integralXtoY = (~cache, f, t) =>
t |> Shape.XYShape.accumulateYs |> CdfLibrary.Distribution.findY(f); t |> XYShape.accumulateYs |> CdfLibrary.Distribution.findY(f);
}); });
module Mixed = module Mixed =
@ -125,16 +131,17 @@ module Mixed =
max(Continuous.maxX(continuous), Discrete.maxX(discrete)); max(Continuous.maxX(continuous), Discrete.maxX(discrete));
let shape = (t: t): DistributionTypes.shape => Mixed(t); let shape = (t: t): DistributionTypes.shape => Mixed(t);
let xToY = let xToY =
(f, {discrete, continuous, discreteProbabilityMassFraction}: t) => (f, {discrete, continuous, discreteProbabilityMassFraction}: t) => {
Mixed({ let c =
continuous: continuous
Continuous.xToY(f, continuous) |> Continuous.xToY(f)
|> YPoint.toContinuousValue |> MixedPoint.fmap(e => e *. (1. -. discreteProbabilityMassFraction));
|> (e => e *. (1. -. discreteProbabilityMassFraction)), let d =
discrete: discrete
Shape.Discrete.findY(f, discrete) |> Discrete.xToY(f)
|> (e => e *. discreteProbabilityMassFraction), |> MixedPoint.fmap(e => e *. discreteProbabilityMassFraction);
}); MixedPoint.add(c, d);
};
let scaledContinuousComponent = let scaledContinuousComponent =
({continuous, discreteProbabilityMassFraction}: t) ({continuous, discreteProbabilityMassFraction}: t)
@ -195,10 +202,8 @@ module Mixed =
let pointwiseFmap = let pointwiseFmap =
(fn, {discrete, continuous, discreteProbabilityMassFraction}: t): t => { (fn, {discrete, continuous, discreteProbabilityMassFraction}: t): t => {
{ {
discrete: Shape.XYShape.pointwiseMap(fn, discrete), discrete: Discrete.pointwiseFmap(fn, discrete),
continuous: continuous: Continuous.pointwiseFmap(fn, continuous),
continuous
|> Shape.Continuous.shapeMap(Shape.XYShape.pointwiseMap(fn)),
discreteProbabilityMassFraction, discreteProbabilityMassFraction,
}; };
}; };
@ -208,16 +213,28 @@ module Shape =
Dist({ Dist({
type t = DistributionTypes.shape; type t = DistributionTypes.shape;
type integral = DistributionTypes.continuousShape; type integral = DistributionTypes.continuousShape;
let mapToAll = (t: t, (fn1, fn2, fn3)) =>
switch (t) {
| Mixed(m) => fn1(m)
| Discrete(m) => fn2(m)
| Continuous(m) => fn3(m)
};
let fmap = (t: t, (fn1, fn2, fn3)): t =>
switch (t) {
| Mixed(m) => Mixed(fn1(m))
| Discrete(m) => Discrete(fn2(m))
| Continuous(m) => Continuous(fn3(m))
};
let xToY = (f, t) => let xToY = (f, t) =>
Shape.T.mapToAll( mapToAll(t, (Mixed.xToY(f), Discrete.xToY(f), Continuous.xToY(f)));
t,
(Mixed.xToY(f), Discrete.xToY(f), Continuous.xToY(f)),
);
let shape = (t: t) => t; let shape = (t: t) => t;
let minX = (t: t) => let minX = (t: t) =>
Shape.T.mapToAll(t, (Mixed.minX, Discrete.minX, Continuous.minX)); mapToAll(t, (Mixed.minX, Discrete.minX, Continuous.minX));
let integral = (~cache, t: t) => let integral = (~cache, t: t) =>
Shape.T.mapToAll( mapToAll(
t, t,
( (
Mixed.Integral.get(~cache), Mixed.Integral.get(~cache),
@ -226,7 +243,7 @@ module Shape =
), ),
); );
let integralSum = (~cache, t: t) => let integralSum = (~cache, t: t) =>
Shape.T.mapToAll( mapToAll(
t, t,
( (
Mixed.Integral.sum(~cache), Mixed.Integral.sum(~cache),
@ -235,7 +252,7 @@ module Shape =
), ),
); );
let integralXtoY = (~cache, f, t) => { let integralXtoY = (~cache, f, t) => {
Shape.T.mapToAll( mapToAll(
t, t,
( (
Mixed.Integral.xToY(~cache, f), Mixed.Integral.xToY(~cache, f),
@ -245,9 +262,9 @@ module Shape =
); );
}; };
let maxX = (t: t) => let maxX = (t: t) =>
Shape.T.mapToAll(t, (Mixed.minX, Discrete.minX, Continuous.minX)); mapToAll(t, (Mixed.minX, Discrete.minX, Continuous.minX));
let pointwiseFmap = (fn, t: t) => let pointwiseFmap = (fn, t: t) =>
Shape.T.fmap( fmap(
t, t,
( (
Mixed.pointwiseFmap(fn), Mixed.pointwiseFmap(fn),
@ -273,7 +290,8 @@ module WithMetadata =
fromShape(Continuous(t.integralCache), t); fromShape(Continuous(t.integralCache), t);
let integralSum = (~cache as _, t: t) => let integralSum = (~cache as _, t: t) =>
t |> shape |> Shape.Integral.sum(~cache=Some(t.integralCache)); t |> shape |> Shape.Integral.sum(~cache=Some(t.integralCache));
// TODO: Fix this below, obviously.
let integralXtoY = (~cache as _, f, t) => { let integralXtoY = (~cache as _, f, t) => {
3.0; 1337.0;
}; };
}); });

View File

@ -1,111 +1,9 @@
open DistributionTypes; open DistributionTypes;
let _lastElement = (a: array('a)) =>
switch (Belt.Array.size(a)) {
| 0 => None
| n => Belt.Array.get(a, n - 1)
};
type pointInRange = type pointInRange =
| Unbounded | Unbounded
| X(float); | X(float);
module XYShape = {
type t = xyShape;
let toJs = (t: t) => {
{"xs": t.xs, "ys": t.ys};
};
let minX = (t: t) => t.xs |> E.A.get(_, 0);
// TODO: Check if this actually gets the last element, I'm not sure it does.
let maxX = (t: t) => t.xs |> (r => E.A.get(r, E.A.length(r) - 1));
let zip = t => Belt.Array.zip(t.xs, t.ys);
let fmap = (t: t, y): t => {xs: t.xs, ys: t.ys |> E.A.fmap(y)};
let pointwiseMap = (fn, t: t): t => {xs: t.xs, ys: t.ys |> E.A.fmap(fn)};
let scaleCdfTo = (~scaleTo=1., t: t) =>
switch (_lastElement(t.ys)) {
| Some(n) =>
let scaleBy = scaleTo /. n;
fmap(t, r => r *. scaleBy);
| None => t
};
let yFold = (fn, t: t) => {
E.A.fold_left(fn, 0., t.ys);
};
let ySum = yFold((a, b) => a +. b);
let fromArray = ((xs, ys)): t => {xs, ys};
let fromArrays = (xs, ys): t => {xs, ys};
let _transverse = fn =>
Belt.Array.reduce(_, [||], (items, (x, y)) =>
switch (_lastElement(items)) {
| Some((xLast, yLast)) =>
Belt.Array.concat(items, [|(x, fn(y, yLast))|])
| None => [|(x, y)|]
}
);
let _transverseShape = (fn, p: t) => {
Belt.Array.zip(p.xs, p.ys)
|> _transverse(fn)
|> Belt.Array.unzip
|> fromArray;
};
let accumulateYs = _transverseShape((aCurrent, aLast) => aCurrent +. aLast);
let subtractYs = _transverseShape((aCurrent, aLast) => aCurrent -. aLast);
module Range = {
// ((lastX, lastY), (nextX, nextY))
type zippedRange = ((float, float), (float, float));
let floatSum = Belt.Array.reduce(_, 0., (a, b) => a +. b);
let toT = r => r |> Belt.Array.unzip |> fromArray;
let nextX = ((_, (nextX, _)): zippedRange) => nextX;
let rangeAreaAssumingSteps =
(((lastX, lastY), (nextX, _)): zippedRange) =>
(nextX -. lastX) *. lastY;
let rangeAreaAssumingTriangles =
(((lastX, lastY), (nextX, nextY)): zippedRange) =>
(nextX -. lastX) *. (lastY +. nextY) /. 2.;
let delta_y_over_delta_x =
(((lastX, lastY), (nextX, nextY)): zippedRange) =>
(nextY -. lastY) /. (nextX -. lastX);
let inRanges = (mapper, reducer, t: t) => {
Belt.Array.zip(t.xs, t.ys)
|> E.A.toRanges
|> E.R.toOption
|> E.O.fmap(r => r |> Belt.Array.map(_, mapper) |> reducer);
};
let mapYsBasedOnRanges = fn => inRanges(r => (nextX(r), fn(r)), toT);
let integrateWithSteps = z =>
mapYsBasedOnRanges(rangeAreaAssumingSteps, z) |> E.O.fmap(accumulateYs);
let integrateWithTriangles = z =>
mapYsBasedOnRanges(rangeAreaAssumingTriangles, z)
|> E.O.fmap(accumulateYs);
let derivative = mapYsBasedOnRanges(delta_y_over_delta_x);
};
let findY = CdfLibrary.Distribution.findY;
let findX = CdfLibrary.Distribution.findX;
};
module Continuous = { module Continuous = {
type t = continuousShape; type t = continuousShape;
let shape = (t: t) => t.shape; let shape = (t: t) => t.shape;
@ -280,20 +178,6 @@ module Mixed = {
module T = { module T = {
type t = DistributionTypes.shape; type t = DistributionTypes.shape;
let mapToAll = (t: t, (fn1, fn2, fn3)) =>
switch (t) {
| Mixed(m) => fn1(m)
| Discrete(m) => fn2(m)
| Continuous(m) => fn3(m)
};
let fmap = (t: t, (fn1, fn2, fn3)) =>
switch (t) {
| Mixed(m) => Mixed(fn1(m))
| Discrete(m) => Discrete(fn2(m))
| Continuous(m) => Continuous(fn3(m))
};
let y = (t: t, x: float) => let y = (t: t, x: float) =>
switch (t) { switch (t) {
| Mixed(m) => `mixed(Mixed.findY(m, x)) | Mixed(m) => `mixed(Mixed.findY(m, x))

99
src/core/XYShape.re Normal file
View File

@ -0,0 +1,99 @@
open DistributionTypes;
let _lastElement = (a: array('a)) =>
switch (Belt.Array.size(a)) {
| 0 => None
| n => Belt.Array.get(a, n - 1)
};
type t = xyShape;
let toJs = (t: t) => {
{"xs": t.xs, "ys": t.ys};
};
let minX = (t: t) => t.xs |> E.A.get(_, 0);
// TODO: Check if this actually gets the last element, I'm not sure it does.
let maxX = (t: t) => t.xs |> (r => E.A.get(r, E.A.length(r) - 1));
let zip = t => Belt.Array.zip(t.xs, t.ys);
let fmap = (t: t, y): t => {xs: t.xs, ys: t.ys |> E.A.fmap(y)};
let pointwiseMap = (fn, t: t): t => {xs: t.xs, ys: t.ys |> E.A.fmap(fn)};
let scaleCdfTo = (~scaleTo=1., t: t) =>
switch (_lastElement(t.ys)) {
| Some(n) =>
let scaleBy = scaleTo /. n;
fmap(t, r => r *. scaleBy);
| None => t
};
let yFold = (fn, t: t) => {
E.A.fold_left(fn, 0., t.ys);
};
let ySum = yFold((a, b) => a +. b);
let fromArray = ((xs, ys)): t => {xs, ys};
let fromArrays = (xs, ys): t => {xs, ys};
let _transverse = fn =>
Belt.Array.reduce(_, [||], (items, (x, y)) =>
switch (_lastElement(items)) {
| Some((xLast, yLast)) =>
Belt.Array.concat(items, [|(x, fn(y, yLast))|])
| None => [|(x, y)|]
}
);
let _transverseShape = (fn, p: t) => {
Belt.Array.zip(p.xs, p.ys)
|> _transverse(fn)
|> Belt.Array.unzip
|> fromArray;
};
let accumulateYs = _transverseShape((aCurrent, aLast) => aCurrent +. aLast);
let subtractYs = _transverseShape((aCurrent, aLast) => aCurrent -. aLast);
module Range = {
// ((lastX, lastY), (nextX, nextY))
type zippedRange = ((float, float), (float, float));
let floatSum = Belt.Array.reduce(_, 0., (a, b) => a +. b);
let toT = r => r |> Belt.Array.unzip |> fromArray;
let nextX = ((_, (nextX, _)): zippedRange) => nextX;
let rangeAreaAssumingSteps = (((lastX, lastY), (nextX, _)): zippedRange) =>
(nextX -. lastX) *. lastY;
let rangeAreaAssumingTriangles =
(((lastX, lastY), (nextX, nextY)): zippedRange) =>
(nextX -. lastX) *. (lastY +. nextY) /. 2.;
let delta_y_over_delta_x =
(((lastX, lastY), (nextX, nextY)): zippedRange) =>
(nextY -. lastY) /. (nextX -. lastX);
let inRanges = (mapper, reducer, t: t) => {
Belt.Array.zip(t.xs, t.ys)
|> E.A.toRanges
|> E.R.toOption
|> E.O.fmap(r => r |> Belt.Array.map(_, mapper) |> reducer);
};
let mapYsBasedOnRanges = fn => inRanges(r => (nextX(r), fn(r)), toT);
let integrateWithSteps = z =>
mapYsBasedOnRanges(rangeAreaAssumingSteps, z) |> E.O.fmap(accumulateYs);
let integrateWithTriangles = z =>
mapYsBasedOnRanges(rangeAreaAssumingTriangles, z)
|> E.O.fmap(accumulateYs);
let derivative = mapYsBasedOnRanges(delta_y_over_delta_x);
};
let findY = CdfLibrary.Distribution.findY;
let findX = CdfLibrary.Distribution.findX;