Separated XYSHape into separate file
This commit is contained in:
parent
0c0fe76e4e
commit
da172bfa94
|
@ -26,11 +26,10 @@ let buildIds = entries => {
|
|||
f.id = curPath ++ "/" ++ genId(f.title, curPath);
|
||||
HS.set(entriesByPath, f.id, FolderEntry(f));
|
||||
f.children
|
||||
|> E.L.iter(e =>
|
||||
switch (e) {
|
||||
|> E.L.iter(
|
||||
fun
|
||||
| CompEntry(c) => processEntry(c, f.id)
|
||||
| FolderEntry(f) => processFolder(f, f.id)
|
||||
}
|
||||
| FolderEntry(f) => processFolder(f, f.id),
|
||||
);
|
||||
}
|
||||
and processEntry = (c: compEntry, curPath) => {
|
||||
|
@ -38,11 +37,10 @@ let buildIds = entries => {
|
|||
HS.set(entriesByPath, c.id, CompEntry(c));
|
||||
};
|
||||
entries
|
||||
|> E.L.iter(e =>
|
||||
switch (e) {
|
||||
|> E.L.iter(
|
||||
fun
|
||||
| CompEntry(c) => processEntry(c, "")
|
||||
| FolderEntry(f) => processFolder(f, "")
|
||||
}
|
||||
| FolderEntry(f) => processFolder(f, ""),
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ let make =
|
|||
marginBottom=50
|
||||
marginTop=0
|
||||
onHover
|
||||
continuous={continuous |> E.O.fmap(Shape.XYShape.toJs)}
|
||||
continuous={continuous |> E.O.fmap(XYShape.toJs)}
|
||||
showDistributionLines
|
||||
showDistributionYAxis
|
||||
showVerticalLine
|
||||
|
|
|
@ -14,26 +14,29 @@ let max = (f1: option(float), f2: option(float)) =>
|
|||
| (None, None) => None
|
||||
};
|
||||
|
||||
type yPoint =
|
||||
| Mixed({
|
||||
type mixedPoint = {
|
||||
continuous: 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);
|
||||
let makeMixed = (c: float, d: float): t =>
|
||||
Mixed({continuous: c, discrete: d});
|
||||
|
||||
module MixedPoint = {
|
||||
type t = mixedPoint;
|
||||
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 = {
|
||||
|
@ -41,7 +44,7 @@ module type dist = {
|
|||
let minX: t => option(float);
|
||||
let maxX: t => option(float);
|
||||
let pointwiseFmap: (float => float, t) => t;
|
||||
let xToY: (float, t) => yPoint;
|
||||
let xToY: (float, t) => mixedPoint;
|
||||
let shape: t => DistributionTypes.shape;
|
||||
|
||||
type integral;
|
||||
|
@ -71,31 +74,33 @@ module Continuous =
|
|||
Dist({
|
||||
type t = 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 integral = (~cache, t) =>
|
||||
cache
|
||||
|> E.O.default(
|
||||
t
|
||||
|> shape
|
||||
|> Shape.XYShape.Range.integrateWithTriangles
|
||||
|> XYShape.Range.integrateWithTriangles
|
||||
|> E.O.toExt("")
|
||||
|> Shape.Continuous.fromShape,
|
||||
|> fromShape,
|
||||
);
|
||||
// This seems wrong, we really want the ending bit, I'd assume
|
||||
let integralSum = (~cache, t) =>
|
||||
t |> integral(~cache) |> shape |> Shape.XYShape.ySum;
|
||||
let minX = (t: t) => t |> shape |> Shape.XYShape.minX;
|
||||
let maxX = (t: t) => t |> shape |> Shape.XYShape.maxX;
|
||||
t |> integral(~cache) |> shape |> XYShape.ySum;
|
||||
let minX = shapeFn(XYShape.minX);
|
||||
let maxX = shapeFn(XYShape.maxX);
|
||||
let pointwiseFmap = (fn, t: t) =>
|
||||
t
|
||||
|> shape
|
||||
|> Shape.XYShape.pointwiseMap(fn)
|
||||
|> Shape.Continuous.fromShape;
|
||||
t |> shape |> XYShape.pointwiseMap(fn) |> fromShape;
|
||||
let shape = (t: t): DistributionTypes.shape => Continuous(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) =>
|
||||
t |> integral(~cache) |> Shape.Continuous.findY(f);
|
||||
t |> integral(~cache) |> shapeFn(CdfLibrary.Distribution.findY(f));
|
||||
});
|
||||
|
||||
module Discrete =
|
||||
|
@ -103,16 +108,17 @@ module Discrete =
|
|||
type t = DistributionTypes.discreteShape;
|
||||
type integral = DistributionTypes.continuousShape;
|
||||
let integral = (~cache, t) =>
|
||||
cache |> E.O.default(t |> Shape.Discrete.integrate);
|
||||
let integralSum = (~cache, t) => t |> Shape.XYShape.ySum;
|
||||
let minX = Shape.XYShape.minX;
|
||||
let maxX = Shape.XYShape.maxX;
|
||||
let pointwiseFmap = Shape.XYShape.pointwiseMap;
|
||||
cache
|
||||
|> E.O.default(t |> XYShape.accumulateYs |> Shape.Continuous.fromShape);
|
||||
let integralSum = (~cache, t) => t |> XYShape.ySum;
|
||||
let minX = XYShape.minX;
|
||||
let maxX = XYShape.maxX;
|
||||
let pointwiseFmap = XYShape.pointwiseMap;
|
||||
let shape = (t: t): DistributionTypes.shape => Discrete(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) =>
|
||||
t |> Shape.XYShape.accumulateYs |> CdfLibrary.Distribution.findY(f);
|
||||
t |> XYShape.accumulateYs |> CdfLibrary.Distribution.findY(f);
|
||||
});
|
||||
|
||||
module Mixed =
|
||||
|
@ -125,16 +131,17 @@ module Mixed =
|
|||
max(Continuous.maxX(continuous), Discrete.maxX(discrete));
|
||||
let shape = (t: t): DistributionTypes.shape => Mixed(t);
|
||||
let xToY =
|
||||
(f, {discrete, continuous, discreteProbabilityMassFraction}: t) =>
|
||||
Mixed({
|
||||
continuous:
|
||||
Continuous.xToY(f, continuous)
|
||||
|> YPoint.toContinuousValue
|
||||
|> (e => e *. (1. -. discreteProbabilityMassFraction)),
|
||||
discrete:
|
||||
Shape.Discrete.findY(f, discrete)
|
||||
|> (e => e *. discreteProbabilityMassFraction),
|
||||
});
|
||||
(f, {discrete, continuous, discreteProbabilityMassFraction}: t) => {
|
||||
let c =
|
||||
continuous
|
||||
|> Continuous.xToY(f)
|
||||
|> MixedPoint.fmap(e => e *. (1. -. discreteProbabilityMassFraction));
|
||||
let d =
|
||||
discrete
|
||||
|> Discrete.xToY(f)
|
||||
|> MixedPoint.fmap(e => e *. discreteProbabilityMassFraction);
|
||||
MixedPoint.add(c, d);
|
||||
};
|
||||
|
||||
let scaledContinuousComponent =
|
||||
({continuous, discreteProbabilityMassFraction}: t)
|
||||
|
@ -195,10 +202,8 @@ module Mixed =
|
|||
let pointwiseFmap =
|
||||
(fn, {discrete, continuous, discreteProbabilityMassFraction}: t): t => {
|
||||
{
|
||||
discrete: Shape.XYShape.pointwiseMap(fn, discrete),
|
||||
continuous:
|
||||
continuous
|
||||
|> Shape.Continuous.shapeMap(Shape.XYShape.pointwiseMap(fn)),
|
||||
discrete: Discrete.pointwiseFmap(fn, discrete),
|
||||
continuous: Continuous.pointwiseFmap(fn, continuous),
|
||||
discreteProbabilityMassFraction,
|
||||
};
|
||||
};
|
||||
|
@ -208,16 +213,28 @@ module Shape =
|
|||
Dist({
|
||||
type t = DistributionTypes.shape;
|
||||
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) =>
|
||||
Shape.T.mapToAll(
|
||||
t,
|
||||
(Mixed.xToY(f), Discrete.xToY(f), Continuous.xToY(f)),
|
||||
);
|
||||
mapToAll(t, (Mixed.xToY(f), Discrete.xToY(f), Continuous.xToY(f)));
|
||||
let shape = (t: 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) =>
|
||||
Shape.T.mapToAll(
|
||||
mapToAll(
|
||||
t,
|
||||
(
|
||||
Mixed.Integral.get(~cache),
|
||||
|
@ -226,7 +243,7 @@ module Shape =
|
|||
),
|
||||
);
|
||||
let integralSum = (~cache, t: t) =>
|
||||
Shape.T.mapToAll(
|
||||
mapToAll(
|
||||
t,
|
||||
(
|
||||
Mixed.Integral.sum(~cache),
|
||||
|
@ -235,7 +252,7 @@ module Shape =
|
|||
),
|
||||
);
|
||||
let integralXtoY = (~cache, f, t) => {
|
||||
Shape.T.mapToAll(
|
||||
mapToAll(
|
||||
t,
|
||||
(
|
||||
Mixed.Integral.xToY(~cache, f),
|
||||
|
@ -245,9 +262,9 @@ module Shape =
|
|||
);
|
||||
};
|
||||
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) =>
|
||||
Shape.T.fmap(
|
||||
fmap(
|
||||
t,
|
||||
(
|
||||
Mixed.pointwiseFmap(fn),
|
||||
|
@ -273,7 +290,8 @@ module WithMetadata =
|
|||
fromShape(Continuous(t.integralCache), t);
|
||||
let integralSum = (~cache as _, t: t) =>
|
||||
t |> shape |> Shape.Integral.sum(~cache=Some(t.integralCache));
|
||||
// TODO: Fix this below, obviously.
|
||||
let integralXtoY = (~cache as _, f, t) => {
|
||||
3.0;
|
||||
1337.0;
|
||||
};
|
||||
});
|
|
@ -1,111 +1,9 @@
|
|||
open DistributionTypes;
|
||||
|
||||
let _lastElement = (a: array('a)) =>
|
||||
switch (Belt.Array.size(a)) {
|
||||
| 0 => None
|
||||
| n => Belt.Array.get(a, n - 1)
|
||||
};
|
||||
|
||||
type pointInRange =
|
||||
| Unbounded
|
||||
| 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 = {
|
||||
type t = continuousShape;
|
||||
let shape = (t: t) => t.shape;
|
||||
|
@ -280,20 +178,6 @@ module Mixed = {
|
|||
module T = {
|
||||
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) =>
|
||||
switch (t) {
|
||||
| Mixed(m) => `mixed(Mixed.findY(m, x))
|
||||
|
|
99
src/core/XYShape.re
Normal file
99
src/core/XYShape.re
Normal 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;
|
Loading…
Reference in New Issue
Block a user