Replaced GenericDistributionChart with ComplexPowerChart

This commit is contained in:
Ozzie Gooen 2020-02-22 20:36:22 +00:00
parent cd1b114295
commit 0d32942110
10 changed files with 155 additions and 486 deletions

View File

@ -8,15 +8,16 @@ let timeDist =
~unit=TimeDistribution({zero: MomentRe.momentNow(), unit: `days}), ~unit=TimeDistribution({zero: MomentRe.momentNow(), unit: `days}),
(), (),
) )
|> GenericDistribution.renderIfNeeded(~sampleCount=1000); |> GenericDistribution.toComplexPower(~sampleCount=1000);
let distributions = () => let distributions = () =>
<div> <div>
<div> <div>
<h2> {"Basic Mixed Distribution" |> ReasonReact.string} </h2> <h2> {"Basic Mixed Distribution" |> ReasonReact.string} </h2>
{timeDist {timeDist
|> E.O.bind(_, GenericDistribution.normalize) |> E.O.React.fmapOrNull(complexPower =>
|> E.O.React.fmapOrNull(dist => <GenericDistributionChart dist />)} <ComplexPowerChart complexPower />
)}
<h2> {"Simple Continuous" |> ReasonReact.string} </h2> <h2> {"Simple Continuous" |> ReasonReact.string} </h2>
</div> </div>
</div>; </div>;

View File

@ -0,0 +1,61 @@
module ComplexPowerChart = {
[@react.component]
let make = (~complexPower: DistributionTypes.complexPower, ~onHover) => {
open DistFunctor.ComplexPower;
let discrete = complexPower |> T.toDiscrete;
let continuous =
complexPower
|> T.toContinuous
|> E.O.fmap(DistFunctor.Continuous.getShape);
let minX = T.minX(complexPower);
let maxX = T.maxX(complexPower);
let timeScale =
complexPower.unit |> DistributionTypes.DistributionUnit.toJson;
<CdfChart__Plain
minX
maxX
?discrete
?continuous
color={`hex("333")}
onHover
timeScale
/>;
};
};
[@react.component]
let make = (~complexPower: DistributionTypes.complexPower) => {
let (x, setX) = React.useState(() => 0.);
let chart =
React.useMemo1(
() => {<ComplexPowerChart complexPower onHover={r => {setX(_ => r)}} />},
[|complexPower|],
);
<div>
chart
<table className="table-auto">
<thead>
<tr>
<th className="px-4 py-2"> {"X Point" |> ReasonReact.string} </th>
<th className="px-4 py-2">
{"Y Integral to Point" |> ReasonReact.string}
</th>
</tr>
</thead>
<tbody>
<tr>
<th className="px-4 py-2 border ">
{x |> E.Float.toString |> ReasonReact.string}
</th>
<th className="px-4 py-2 border ">
{complexPower
|> DistFunctor.ComplexPower.T.Integral.xToY(~cache=None, x)
|> E.Float.with2DigitsPrecision
|> ReasonReact.string}
</th>
</tr>
</tbody>
</table>
<div />
</div>;
};

View File

@ -1,77 +0,0 @@
module Shapee = {
[@react.component]
let make = (~shape: DistributionTypes.shape, ~timeScale, ~onHover) => {
<div
// let discrete = Shape.T.scaledDiscreteComponent(shape);
// let continuous = Shape.T.scaledContinuousComponent(shape);
// <div>
// <CdfChart__Plain
// minX={Shape.T.minX(shape)}
// maxX={Shape.T.maxX(shape)}
// ?discrete
// ?continuous
// color={`hex("333")}
// onHover
// timeScale
// />
// {discrete |> E.O.React.fmapOrNull(Shape.Discrete.render)}
// </div>;
/>;
};
};
module GenericDist = {
[@react.component]
let make = (~genericDistribution: DistributionTypes.genericDistribution) => {
let (x, setX) = React.useState(() => 0.);
let timeScale =
genericDistribution.unit |> DistributionTypes.DistributionUnit.toJson;
let chart =
React.useMemo1(
() => {
genericDistribution
|> DistributionTypes.shapee
|> E.O.React.fmapOrNull(shape => {
<Shapee shape timeScale onHover={r => setX(_ => r)} />
})
},
[|genericDistribution|],
);
<div>
chart
<table className="table-auto">
<thead>
<tr>
<th className="px-4 py-2"> {"X Point" |> ReasonReact.string} </th>
<th className="px-4 py-2">
{"Y Integral to Point" |> ReasonReact.string}
</th>
</tr>
</thead>
<tbody>
<tr>
<th className="px-4 py-2 border ">
{x |> E.Float.toString |> ReasonReact.string}
</th>
<th className="px-4 py-2 border ">
{genericDistribution->GenericDistribution.yIntegral(x)
|> E.O.fmap(E.Float.with2DigitsPrecision)
|> E.O.default("")
|> ReasonReact.string}
</th>
</tr>
</tbody>
</table>
<div />
</div>;
};
};
[@react.component]
let make = (~dist) => {
switch ((dist: DistributionTypes.genericDistribution)) {
| {generationSource: Shape(_)} =>
<div> <GenericDist genericDistribution=dist /> </div>
| _ => <div />
};
};

View File

@ -324,7 +324,7 @@ module Shape = {
); );
}; };
let maxX = (t: t) => let maxX = (t: t) =>
mapToAll(t, (Mixed.T.minX, Discrete.T.minX, Continuous.T.minX)); mapToAll(t, (Mixed.T.maxX, Discrete.T.maxX, Continuous.T.maxX));
let pointwiseFmap = (fn, t: t) => let pointwiseFmap = (fn, t: t) =>
fmap( fmap(
t, t,
@ -337,7 +337,36 @@ module Shape = {
}); });
}; };
module WithMetadata = { module ComplexPower = {
open DistributionTypes;
let make =
(
~shape,
~guesstimatorString,
~domain=Complete,
~unit=UnspecifiedDistribution,
(),
)
: complexPower => {
let integral = Shape.T.Integral.get(~cache=None, shape);
{shape, domain, integralCache: integral, unit, guesstimatorString};
};
let update =
(
~shape=?,
~integralCache=?,
~domain=?,
~unit=?,
~guesstimatorString=?,
t: complexPower,
) => {
shape: E.O.default(t.shape, shape),
integralCache: E.O.default(t.integralCache, integralCache),
domain: E.O.default(t.domain, domain),
unit: E.O.default(t.unit, unit),
guesstimatorString: E.O.default(t.guesstimatorString, guesstimatorString),
};
module T = module T =
Dist({ Dist({
type t = DistributionTypes.complexPower; type t = DistributionTypes.complexPower;
@ -350,7 +379,7 @@ module WithMetadata = {
let xToY = f => shapeFn(Shape.T.xToY(f)); let xToY = f => shapeFn(Shape.T.xToY(f));
let minX = shapeFn(Shape.T.minX); let minX = shapeFn(Shape.T.minX);
let maxX = shapeFn(Shape.T.maxX); let maxX = shapeFn(Shape.T.maxX);
let fromShape = (shape, t): t => DistributionTypes.update(~shape, t); let fromShape = (shape, t): t => update(~shape, t);
// todo: adjust for limit // todo: adjust for limit
let pointwiseFmap = (fn, {shape, _} as t: t): t => let pointwiseFmap = (fn, {shape, _} as t: t): t =>
fromShape(Shape.T.pointwiseFmap(fn, shape), t); fromShape(Shape.T.pointwiseFmap(fn, shape), t);

View File

@ -66,29 +66,12 @@ type genericDistribution = {
unit: distributionUnit, unit: distributionUnit,
}; };
let shapee = ({generationSource}: genericDistribution) =>
switch (generationSource) {
| GuesstimatorString(_) => None
| Shape(pointsType) => Some(pointsType)
};
type pdfCdfCombo = {
pdf: shape,
cdf: continuousShape,
};
type complexPower = { type complexPower = {
shape, shape,
domain,
integralCache: continuousShape, integralCache: continuousShape,
domain: domainLimit,
unit: distributionUnit, unit: distributionUnit,
}; guesstimatorString: option(string),
let update = (~shape=?, ~integralCache=?, ~domain=?, ~unit=?, t: complexPower) => {
shape: E.O.default(t.shape, shape),
integralCache: E.O.default(t.integralCache, integralCache),
domain: E.O.default(t.domain, domain),
unit: E.O.default(t.unit, unit),
}; };
module DistributionUnit = { module DistributionUnit = {
@ -102,6 +85,34 @@ module DistributionUnit = {
}; };
}; };
module Domain = {
let excludedProbabilityMass = (t: domain) => {
switch (t) {
| Complete => 1.0
| LeftLimited({excludingProbabilityMass}) => excludingProbabilityMass
| RightLimited({excludingProbabilityMass}) => excludingProbabilityMass
| LeftAndRightLimited(
{excludingProbabilityMass: l},
{excludingProbabilityMass: r},
) =>
l +. r
};
};
let initialProbabilityMass = (t: domain) => {
switch (t) {
| Complete
| RightLimited(_) => 0.0
| LeftLimited({excludingProbabilityMass}) => excludingProbabilityMass
| LeftAndRightLimited({excludingProbabilityMass}, _) => excludingProbabilityMass
};
};
let normalizeProbabilityMass = (t: domain) => {
1. /. excludedProbabilityMass(t);
};
};
type mixedPoint = { type mixedPoint = {
continuous: float, continuous: float,
discrete: float, discrete: float,

View File

@ -1,33 +1,5 @@
open DistributionTypes; open DistributionTypes;
module Domain = {
let excludedProbabilityMass = (t: DistributionTypes.domain) => {
switch (t) {
| Complete => 1.0
| LeftLimited({excludingProbabilityMass}) => excludingProbabilityMass
| RightLimited({excludingProbabilityMass}) => excludingProbabilityMass
| LeftAndRightLimited(
{excludingProbabilityMass: l},
{excludingProbabilityMass: r},
) =>
l +. r
};
};
let initialProbabilityMass = (t: DistributionTypes.domain) => {
switch (t) {
| Complete
| RightLimited(_) => 0.0
| LeftLimited({excludingProbabilityMass}) => excludingProbabilityMass
| LeftAndRightLimited({excludingProbabilityMass}, _) => excludingProbabilityMass
};
};
let normalizeProbabilityMass = (t: DistributionTypes.domain) => {
1. /. excludedProbabilityMass(t);
};
};
let make = let make =
( (
~generationSource, ~generationSource,
@ -43,51 +15,23 @@ let make =
unit, unit,
}; };
//TODO: The fact that it is a CDF is really something you find later, this can't be chosen until GuesstimatorToString happens. let toComplexPower =
let renderIfNeeded = (~sampleCount, t: genericDistribution): option(complexPower) => {
(~sampleCount=1000, t: genericDistribution): option(genericDistribution) => { let shape =
switch (t.generationSource) { switch (t.generationSource) {
| GuesstimatorString(s) => | GuesstimatorString(s) =>
Guesstimator.stringToMixedShape(~string=s, ~sampleCount, ()) Guesstimator.stringToMixedShape(~string=s, ~sampleCount, ())
|> E.O.bind(_, DistFunctor.Mixed.clean) |> E.O.bind(_, DistFunctor.Mixed.clean)
|> E.O.fmap((shape: DistributionTypes.shape) => | Shape(shape) => Some(shape)
make( };
~generationSource=Shape(shape), shape
~probabilityType=Pdf, |> E.O.fmap(shape =>
~domain=t.domain, DistFunctor.ComplexPower.make(
~unit=t.unit, ~shape,
(), ~domain=t.domain,
) ~unit=t.unit,
~guesstimatorString=None,
(),
) )
| Shape(_) => Some(t) );
};
};
let normalize = (t: genericDistribution): option(genericDistribution) => {
switch (t.generationSource) {
| Shape(shape) => Some({...t, generationSource: Shape(shape)})
| GuesstimatorString(_) => Some(t)
};
};
let yIntegral = (t: DistributionTypes.genericDistribution, x) => {
switch (t) {
| {generationSource: Shape(shape)} =>
Some(DistFunctor.Shape.T.Integral.xToY(~cache=None, x, shape))
| _ => None
};
};
// TODO: This obviously needs to be fleshed out a lot.
let integrate = (t: DistributionTypes.genericDistribution) => {
switch (t) {
| {probabilityType: Pdf, generationSource: Shape(shape), domain, unit} =>
Some({
generationSource: Shape(shape),
probabilityType: Pdf,
domain,
unit,
})
| _ => None
};
}; };

View File

@ -1,297 +0,0 @@
open DistributionTypes;
type pointInRange =
| Unbounded
| X(float);
module Continuous = {
type t = continuousShape;
let xyShape = (t: t) => t.xyShape;
let getShape = (t: t) => t.xyShape;
let interpolation = (t: t) => t.interpolation;
let make = (xyShape, interpolation): t => {xyShape, interpolation};
let fromShape = xyShape => make(xyShape, `Linear);
let shapeMap = (fn, {xyShape, interpolation}: t): t => {
xyShape: fn(xyShape),
interpolation,
};
let oShapeMap =
(fn, {xyShape, interpolation}: t)
: option(DistributionTypes.continuousShape) =>
fn(xyShape) |> E.O.fmap(xyShape => make(xyShape, interpolation));
let shapeFn = (fn, t: t) => t |> xyShape |> fn;
let minX = shapeFn(XYShape.minX);
let maxX = shapeFn(XYShape.maxX);
let findX = y => shapeFn(CdfLibrary.Distribution.findX(y));
let findY = x => shapeFn(CdfLibrary.Distribution.findY(x));
let toJs = shapeFn(XYShape.toJs);
let fromArrays = (a, b) => make(XYShape.fromArrays(a, b), `Linear);
let toPdf = (t: t) => t |> oShapeMap(XYShape.Range.derivative);
let toCdf = (t: t) => t |> oShapeMap(XYShape.Range.integrateWithTriangles);
let findIntegralY = (f, t) => {
t
|> toCdf
|> E.O.fmap(xyShape)
|> E.O.fmap(CdfLibrary.Distribution.findY(f));
};
let normalizeCdf = (continuousShape: continuousShape) =>
continuousShape
|> xyShape
|> XYShape.scaleCdfTo(~scaleTo=1.0)
|> fromShape;
let scalePdf = (~scaleTo=1.0, continuousShape: continuousShape) => {
switch (toCdf(continuousShape)) {
| Some({xyShape}) =>
XYShape.scaleCdfTo(~scaleTo, xyShape)
|> XYShape.Range.derivative
|> E.O.fmap(fromShape)
| _ => None
};
};
};
module Discrete = {
let minX = XYShape.minX;
let maxX = XYShape.maxX;
type t = discreteShape;
let fromArrays = XYShape.fromArrays;
let toJs = XYShape.toJs;
let ySum = XYShape.ySum;
let zip = t => Belt.Array.zip(t.xs, t.ys);
let pointwiseMap = (t: discreteShape, fn): discreteShape => {
xs: t.xs,
ys: t.ys |> E.A.fmap(fn),
};
let scaleYToTotal = (totalDesired, t: t): t => {
let difference = totalDesired /. ySum(t);
XYShape.fmap(t, y => y *. difference);
};
let render = (t: t) =>
Belt.Array.zip(t.xs, t.ys)
|> E.A.fmap(((x, y)) =>
<div>
{E.Float.toFixed(x)
++ "---"
++ E.Float.with3DigitsPrecision(y *. 100.)
|> ReasonReact.string}
</div>
)
|> ReasonReact.array;
let integrate = t => t |> XYShape.accumulateYs |> Continuous.fromShape;
let derivative = XYShape.subtractYs;
// TODO: This has a clear bug where it returns the Y value of the first item,
// even if X is less than the X of the first item.
// It has a second bug that it assumes things are triangular, instead of interpolating via steps.
let findIntegralY = (f, t: t) => {
t |> XYShape.accumulateYs |> CdfLibrary.Distribution.findY(f);
};
let findY = (f, t: t) => {
Belt.Array.zip(t.xs, t.ys)
|> E.A.getBy(_, ((x, _)) => x == f)
|> E.O.fmap(((_, y)) => y)
|> E.O.default(0.);
};
};
let min = (f1: option(float), f2: option(float)) =>
switch (f1, f2) {
| (Some(f1), Some(f2)) => Some(f1 < f2 ? f1 : f2)
| (Some(f1), None) => Some(f1)
| (None, Some(f2)) => Some(f2)
| (None, None) => None
};
let max = (f1: option(float), f2: option(float)) =>
switch (f1, f2) {
| (Some(f1), Some(f2)) => Some(f1 > f2 ? f1 : f2)
| (Some(f1), None) => Some(f1)
| (None, Some(f2)) => Some(f2)
| (None, None) => None
};
module Mixed = {
// let make = (~continuous, ~discrete, ~discreteProbabilityMassFraction) => {
// continuous,
// discrete,
// discreteProbabilityMassFraction,
// };
let minX = (t: DistributionTypes.mixedShape) =>
min(t.continuous |> Continuous.minX, t.discrete |> Discrete.minX);
let maxX = (t: DistributionTypes.mixedShape) => {
max(t.continuous |> Continuous.maxX, t.discrete |> Discrete.maxX);
};
let mixedMultiply =
(
t: DistributionTypes.mixedShape,
continuousComponent,
discreteComponent,
) => {
let diffFn = t.discreteProbabilityMassFraction;
continuousComponent *. (1.0 -. diffFn) +. discreteComponent *. diffFn;
};
type yPdfPoint = {
continuous: option(float),
discrete: option(float),
};
let findY = (t: DistributionTypes.mixedShape, x: float): yPdfPoint => {
continuous:
Continuous.findY(x, t.continuous)
|> (e => e *. (1. -. t.discreteProbabilityMassFraction))
|> E.O.some,
discrete:
Discrete.findY(x, t.discrete)
|> (e => e *. t.discreteProbabilityMassFraction)
|> E.O.some,
};
let findYIntegral =
(x: float, t: DistributionTypes.mixedShape): option(float) => {
let c = t.continuous |> Continuous.findIntegralY(x);
let d = Discrete.findIntegralY(x, t.discrete);
switch (c, d) {
| (Some(c), d) => Some(mixedMultiply(t, c, d))
| _ => None
};
};
} /* }*/;
// module T = {
// type t = DistributionTypes.shape;
// let y = (t: t, x: float) =>
// switch (t) {
// | Mixed(m) => `mixed(Mixed.findY(m, x))
// | Discrete(discreteShape) => `discrete(Discrete.findY(x, discreteShape))
// | Continuous(continuousShape) =>
// `continuous(Continuous.findY(x, continuousShape))
// };
// let yIntegral = (t: t, x: float) =>
// switch (t) {
// | Mixed(m) => Mixed.findYIntegral(x, m)
// | Discrete(discreteShape) =>
// Discrete.findIntegralY(x, discreteShape) |> E.O.some
// | Continuous(continuousShape) =>
// Continuous.findIntegralY(x, continuousShape)
// };
// let minX = (t: t) =>
// switch (t) {
// | Mixed(m) => Mixed.minX(m)
// | Discrete(discreteShape) => Discrete.minX(discreteShape)
// | Continuous(continuousShape) => Continuous.minX(continuousShape)
// };
// let maxX = (t: t) =>
// switch (t) {
// | Mixed(m) => Mixed.maxX(m)
// | Discrete(discreteShape) => Discrete.maxX(discreteShape)
// | Continuous(continuousShape) => Continuous.maxX(continuousShape)
// };
// let discreteComponent = (t: t) =>
// switch (t) {
// | Mixed({discrete}) => Some(discrete)
// | Discrete(d) => Some(d)
// | Continuous(_) => None
// };
// let continuousComponent = (t: t) =>
// switch (t) {
// | Mixed({continuous}) => Some(continuous)
// | Continuous(c) => Some(c)
// | Discrete(_) => None
// };
// // let scaledContinuousComponent = (t: t): option(continuousShape) => {
// // switch (t) {
// // | Mixed({continuous, discreteProbabilityMassFraction}) =>
// // Continuous.scalePdf(
// // ~scaleTo=1.0 -. discreteProbabilityMassFraction,
// // continuous,
// // )
// // | Discrete(_) => None
// // | Continuous(c) => Some(c)
// // };
// // };
// // let scaledDiscreteComponent = (t: t): option(discreteShape) => {
// // switch (t) {
// // | Mixed({discrete, discreteProbabilityMassFraction}) =>
// // Some(Discrete.scaleYToTotal(discreteProbabilityMassFraction, discrete))
// // | Discrete(d) => Some(d)
// // | Continuous(_) => None
// // };
// // };
// // let pointwiseFmap = (fn, t: t): shape =>
// // switch (t) {
// // | Mixed({discrete, continuous, discreteProbabilityMassFraction}) =>
// // Mixed({
// // continuous: XYShape.pointwiseMap(fn, continuous),
// // discrete: XYShape.pointwiseMap(fn, discrete),
// // discreteProbabilityMassFraction,
// // })
// // | Discrete(x) => Discrete(XYShape.pointwiseMap(fn, x))
// // | Continuous(x) => Continuous(XYShape.pointwiseMap(fn, x))
// // };
// // module Cdf = {
// // let normalizeCdf = (t: DistributionTypes.shape) => {
// // switch (t) {
// // | Mixed({continuous, discrete, discreteProbabilityMassFraction}) =>
// // Mixed({
// // continuous: continuous |> Continuous.normalizeCdf,
// // discrete: discrete |> Discrete.scaleYToTotal(1.0),
// // discreteProbabilityMassFraction,
// // })
// // | Discrete(d) => Discrete(d |> Discrete.scaleYToTotal(1.0))
// // | Continuous(continuousShape) =>
// // Continuous(Continuous.normalizeCdf(continuousShape))
// // };
// // };
// // };
// };
// module PdfCdfShape = {
// type t = pdfCdfCombo;
// let pdf = (t: t) =>
// switch (t.pdf) {
// | Mixed(pdf) => Mixed(pdf)
// | Discrete(pdf) => Discrete(pdf)
// | Continuous(pdf) => Continuous(pdf)
// };
// let cdf = (t: t) => t.cdf;
// };
// type distributionUnit =
// | UnspecifiedDistribution
// | TimeDistribution(TimeTypes.timeVector);
// type withLimitedDomain = {
// domain,
// dist: pdfCdfCombo,
// };
// module WithLimitedDomain = {
// type t = withLimitedDomain;
// let dist = (t: t) => t.dist;
// let pdf = (t: t) => PdfCdfShape.pdf(t.dist);
// let cdf = (t: t) => PdfCdfShape.cdf(t.dist);
// // TODO: This is bad, obviously needs to be fixed.
// let distScaleFactor = (t: t) => 3.0;
// // let scaledPdfShape = (scaleFactor, t: t) =>
// // t |> pdf |> T.pointwiseFmap(r => r *. scaleFactor);
// // let scaledCdfShape = (scaleFactor, t: t) =>
// // t |> cdf |> XYShape.pointwiseMap(r => r *. scaleFactor);
// };
// type withTimeVector = {
// timeVector: TimeTypes.timeVector,
// dist: withLimitedDomain,

View File

@ -19,15 +19,11 @@ let propValue = (t: Prop.Value.t) => {
| ConditionalArray(r) => "Array" |> ReasonReact.string | ConditionalArray(r) => "Array" |> ReasonReact.string
| GenericDistribution(r) => | GenericDistribution(r) =>
let newDistribution = let newDistribution =
GenericDistribution.renderIfNeeded(~sampleCount=2000, r); GenericDistribution.toComplexPower(~sampleCount=1000, r);
switch (newDistribution) { switch (newDistribution) {
| Some(distribution) => | Some(distribution) =>
<div> <div> <ComplexPowerChart complexPower=distribution /> </div>
{GenericDistribution.normalize(distribution)
|> E.O.React.fmapOrNull(dist => <GenericDistributionChart dist />)}
</div>
| None => "Something went wrong" |> ReasonReact.string | None => "Something went wrong" |> ReasonReact.string
| _ => <div />
}; };
| FloatCdf(_) => <div /> | FloatCdf(_) => <div />
| Probability(r) => | Probability(r) =>

View File

@ -112,12 +112,11 @@ module Model = {
let model = GlobalCatastrophe.Model.make(dateTime); let model = GlobalCatastrophe.Model.make(dateTime);
switch (model) { switch (model) {
| Prop.Value.GenericDistribution(genericDistribution) => | Prop.Value.GenericDistribution(genericDistribution) =>
GenericDistribution.renderIfNeeded( genericDistribution
~sampleCount=1000, |> GenericDistribution.toComplexPower(~sampleCount=1000)
genericDistribution, |> E.O.fmap(
) DistFunctor.ComplexPower.T.Integral.xToY(~cache=None, 18.0),
|> E.O.bind(_, GenericDistribution.normalize) )
|> E.O.bind(_, GenericDistribution.yIntegral(_, 18.0))
| _ => None | _ => None
}; };
}; };

View File

@ -17,7 +17,9 @@ module Internals = {
}; };
let toContinous = (r: combined) => let toContinous = (r: combined) =>
continuousGet(r) |> CdfLibrary.JS.jsToDist |> Shape.Continuous.fromShape; continuousGet(r)
|> CdfLibrary.JS.jsToDist
|> DistFunctor.Continuous.fromShape;
let toDiscrete = (r: combined): DistributionTypes.xyShape => let toDiscrete = (r: combined): DistributionTypes.xyShape =>
discreteGet(r) |> jsToDistDiscrete; discreteGet(r) |> jsToDistDiscrete;