Simple minX and maxX for distributions
This commit is contained in:
parent
73dbd64686
commit
c3ca1a1a57
|
@ -16,15 +16,13 @@ let mixedDist =
|
||||||
)
|
)
|
||||||
|> GenericDistribution.renderIfNeeded(~sampleCount=1000);
|
|> GenericDistribution.renderIfNeeded(~sampleCount=1000);
|
||||||
|
|
||||||
|
// "mm(floor(uniform(30,35)), normal(50,20), [.25,.5])",
|
||||||
let timeDist =
|
let timeDist =
|
||||||
GenericDistribution.make(
|
GenericDistribution.make(
|
||||||
~generationSource=
|
~generationSource=GuesstimatorString("floor(normal(30,2))"),
|
||||||
GuesstimatorString(
|
|
||||||
"mm(floor(uniform(40, 50)), normal(50,10), [.5,.5])",
|
|
||||||
),
|
|
||||||
~probabilityType=Pdf,
|
~probabilityType=Pdf,
|
||||||
~domain=Complete,
|
~domain=Complete,
|
||||||
~unit=TimeDistribution({zero: MomentRe.momentNow(), unit: `years}),
|
~unit=TimeDistribution({zero: MomentRe.momentNow(), unit: `days}),
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
|> GenericDistribution.renderIfNeeded(~sampleCount=1000);
|
|> GenericDistribution.renderIfNeeded(~sampleCount=1000);
|
||||||
|
|
|
@ -63,38 +63,55 @@ let continuousComponent = (p: DistributionTypes.pointsType) =>
|
||||||
| Continuous(c) => Some(c)
|
| Continuous(c) => Some(c)
|
||||||
};
|
};
|
||||||
|
|
||||||
module Cont = {
|
let discreteScaleFactor = (p: DistributionTypes.pointsType) =>
|
||||||
[@react.component]
|
switch (p) {
|
||||||
let make = (~continuous, ~onHover, ~timeScale) => {
|
| Mixed(mixedShape) => Some(mixedShape.discreteProbabilityMassFraction)
|
||||||
let chart =
|
| Discrete(_) => None
|
||||||
React.useMemo1(
|
| Continuous(_) => None
|
||||||
() =>
|
|
||||||
<CdfChart__Plain
|
|
||||||
primaryDistribution=continuous
|
|
||||||
color={`hex("333")}
|
|
||||||
onHover
|
|
||||||
timeScale
|
|
||||||
/>,
|
|
||||||
[|continuous|],
|
|
||||||
);
|
|
||||||
chart;
|
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
module Shapee = {
|
module Shapee = {
|
||||||
[@react.component]
|
[@react.component]
|
||||||
let make = (~shape: DistributionTypes.pointsType, ~timeScale, ~onHover) => {
|
let make = (~shape: DistributionTypes.pointsType, ~timeScale, ~onHover) => {
|
||||||
let continuous = continuousComponent(shape);
|
let discreteScaleFactor = shape |> discreteScaleFactor;
|
||||||
let discrete = discreteComponent(shape);
|
let continuous =
|
||||||
|
continuousComponent(shape)
|
||||||
|
|> E.O.bind(
|
||||||
|
_,
|
||||||
|
Shape.Continuous.scalePdf(
|
||||||
|
~scaleTo=
|
||||||
|
discreteScaleFactor
|
||||||
|
|> E.O.fmap(r => 1. -. r)
|
||||||
|
|> E.O.default(1.0),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
let discrete =
|
||||||
|
discreteComponent(shape)
|
||||||
|
|> E.O.fmap(
|
||||||
|
Shape.Discrete.scaleYToTotal(
|
||||||
|
discreteScaleFactor |> E.O.default(1.0),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
let minX = {
|
||||||
|
Shape.Any.minX(shape);
|
||||||
|
};
|
||||||
|
let maxX = {
|
||||||
|
Shape.Any.maxX(shape);
|
||||||
|
};
|
||||||
<div>
|
<div>
|
||||||
{continuous
|
{continuous
|
||||||
|> E.O.React.fmapOrNull(continuous =>
|
|> E.O.React.fmapOrNull(continuous =>
|
||||||
<Cont continuous onHover timeScale />
|
<CdfChart__Plain
|
||||||
)}
|
primaryDistribution=continuous
|
||||||
{discrete
|
minX
|
||||||
|> E.O.React.fmapOrNull(r =>
|
maxX
|
||||||
r |> Shape.Discrete.scaleYToTotal(0.3) |> Shape.Discrete.render
|
?discrete
|
||||||
|
color={`hex("333")}
|
||||||
|
onHover
|
||||||
|
timeScale
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
|
{discrete |> E.O.React.fmapOrNull(Shape.Discrete.render)}
|
||||||
</div>;
|
</div>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -105,12 +122,19 @@ module GenericDist = {
|
||||||
let (x, setX) = React.useState(() => 0.);
|
let (x, setX) = React.useState(() => 0.);
|
||||||
let timeScale =
|
let timeScale =
|
||||||
genericDistribution.unit |> DistributionTypes.DistributionUnit.toJson;
|
genericDistribution.unit |> DistributionTypes.DistributionUnit.toJson;
|
||||||
<div>
|
let chart =
|
||||||
{genericDistribution
|
React.useMemo1(
|
||||||
|
() => {
|
||||||
|
genericDistribution
|
||||||
|> DistributionTypes.shape
|
|> DistributionTypes.shape
|
||||||
|> E.O.React.fmapOrNull(shape => {
|
|> E.O.React.fmapOrNull(shape => {
|
||||||
<Shapee shape timeScale onHover={r => setX(_ => r)} />
|
<Shapee shape timeScale onHover={r => setX(_ => r)} />
|
||||||
})}
|
})
|
||||||
|
},
|
||||||
|
[|genericDistribution|],
|
||||||
|
);
|
||||||
|
<div>
|
||||||
|
chart
|
||||||
<table className="table-auto">
|
<table className="table-auto">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
|
|
@ -20,10 +20,26 @@ let renderIfNeeded =
|
||||||
switch (t.generationSource) {
|
switch (t.generationSource) {
|
||||||
| GuesstimatorString(s) =>
|
| GuesstimatorString(s) =>
|
||||||
let shape = Guesstimator.stringToMixedShape(~string=s, ~sampleCount, ());
|
let shape = Guesstimator.stringToMixedShape(~string=s, ~sampleCount, ());
|
||||||
shape
|
let newShape =
|
||||||
|> E.O.fmap((shape: DistributionTypes.mixedShape) =>
|
switch (shape) {
|
||||||
|
| Some({
|
||||||
|
continuous: {xs: [||], ys: [||]},
|
||||||
|
discrete: {xs: [||], ys: [||]},
|
||||||
|
}) =>
|
||||||
|
None
|
||||||
|
| Some({continuous, discrete: {xs: [||], ys: [||]}}) =>
|
||||||
|
Some(Continuous(continuous))
|
||||||
|
| Some({continuous: {xs: [||], ys: [||]}, discrete}) =>
|
||||||
|
Some(Discrete(discrete))
|
||||||
|
| Some(shape) => Some(Mixed(shape))
|
||||||
|
| _ => None
|
||||||
|
};
|
||||||
|
|
||||||
|
Js.log(newShape);
|
||||||
|
newShape
|
||||||
|
|> E.O.fmap((shape: DistributionTypes.pointsType) =>
|
||||||
make(
|
make(
|
||||||
~generationSource=Shape(Mixed(shape)),
|
~generationSource=Shape(shape),
|
||||||
~probabilityType=Cdf,
|
~probabilityType=Cdf,
|
||||||
~domain=t.domain,
|
~domain=t.domain,
|
||||||
~unit=t.unit,
|
~unit=t.unit,
|
||||||
|
@ -52,7 +68,7 @@ let normalizePdf = (t: DistributionTypes.pointsType) => {
|
||||||
switch (t) {
|
switch (t) {
|
||||||
| Mixed({continuous, discrete, discreteProbabilityMassFraction}) =>
|
| Mixed({continuous, discrete, discreteProbabilityMassFraction}) =>
|
||||||
continuous
|
continuous
|
||||||
|> Shape.Continuous.normalizePdf
|
|> Shape.Continuous.scalePdf(~scaleTo=1.0)
|
||||||
|> E.O.fmap(r =>
|
|> E.O.fmap(r =>
|
||||||
Mixed({
|
Mixed({
|
||||||
continuous: r,
|
continuous: r,
|
||||||
|
@ -63,7 +79,7 @@ let normalizePdf = (t: DistributionTypes.pointsType) => {
|
||||||
| Discrete(d) => Some(Discrete(d |> Shape.Discrete.scaleYToTotal(1.0)))
|
| Discrete(d) => Some(Discrete(d |> Shape.Discrete.scaleYToTotal(1.0)))
|
||||||
| Continuous(continuousShape) =>
|
| Continuous(continuousShape) =>
|
||||||
continuousShape
|
continuousShape
|
||||||
|> Shape.Continuous.normalizePdf
|
|> Shape.Continuous.scalePdf(~scaleTo=1.0)
|
||||||
|> E.O.fmap(r => Continuous(r))
|
|> E.O.fmap(r => Continuous(r))
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,6 +17,10 @@ module XYShape = {
|
||||||
{"xs": t.xs, "ys": t.ys};
|
{"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 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 fmap = (t: t, y): t => {xs: t.xs, ys: t.ys |> E.A.fmap(y)};
|
||||||
|
@ -101,6 +105,8 @@ module XYShape = {
|
||||||
};
|
};
|
||||||
|
|
||||||
module Continuous = {
|
module Continuous = {
|
||||||
|
let minX = XYShape.minX;
|
||||||
|
let maxX = XYShape.maxX;
|
||||||
let fromArrays = XYShape.fromArrays;
|
let fromArrays = XYShape.fromArrays;
|
||||||
let toJs = XYShape.toJs;
|
let toJs = XYShape.toJs;
|
||||||
let toPdf = XYShape.Range.derivative;
|
let toPdf = XYShape.Range.derivative;
|
||||||
|
@ -114,11 +120,16 @@ module Continuous = {
|
||||||
let normalizeCdf = (continuousShape: continuousShape) =>
|
let normalizeCdf = (continuousShape: continuousShape) =>
|
||||||
continuousShape |> XYShape.scaleCdfTo(~scaleTo=1.0);
|
continuousShape |> XYShape.scaleCdfTo(~scaleTo=1.0);
|
||||||
|
|
||||||
let normalizePdf = (continuousShape: continuousShape) =>
|
let scalePdf = (~scaleTo=1.0, continuousShape: continuousShape) =>
|
||||||
continuousShape |> toCdf |> E.O.fmap(normalizeCdf) |> E.O.bind(_, toPdf);
|
continuousShape
|
||||||
|
|> toCdf
|
||||||
|
|> E.O.fmap(XYShape.scaleCdfTo(~scaleTo))
|
||||||
|
|> E.O.bind(_, toPdf);
|
||||||
};
|
};
|
||||||
|
|
||||||
module Discrete = {
|
module Discrete = {
|
||||||
|
let minX = XYShape.minX;
|
||||||
|
let maxX = XYShape.maxX;
|
||||||
type t = discreteShape;
|
type t = discreteShape;
|
||||||
let fromArrays = XYShape.fromArrays;
|
let fromArrays = XYShape.fromArrays;
|
||||||
let toJs = XYShape.toJs;
|
let toJs = XYShape.toJs;
|
||||||
|
@ -147,6 +158,7 @@ module Discrete = {
|
||||||
|
|
||||||
// TODO: This has a clear bug where it returns the Y value of the first item,
|
// 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.
|
// 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) => {
|
let findIntegralY = (f, t: t) => {
|
||||||
t |> XYShape.accumulateYs |> CdfLibrary.Distribution.findY(f);
|
t |> XYShape.accumulateYs |> CdfLibrary.Distribution.findY(f);
|
||||||
};
|
};
|
||||||
|
@ -159,6 +171,22 @@ module Discrete = {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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 = {
|
module Mixed = {
|
||||||
let make = (~continuous, ~discrete, ~discreteProbabilityMassFraction) => {
|
let make = (~continuous, ~discrete, ~discreteProbabilityMassFraction) => {
|
||||||
continuous,
|
continuous,
|
||||||
|
@ -166,6 +194,12 @@ module Mixed = {
|
||||||
discreteProbabilityMassFraction,
|
discreteProbabilityMassFraction,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let minX = (t: DistributionTypes.mixedShape) =>
|
||||||
|
min(t.continuous |> Continuous.minX, t.discrete |> Discrete.minX);
|
||||||
|
|
||||||
|
let maxX = (t: DistributionTypes.mixedShape) =>
|
||||||
|
min(t.continuous |> Continuous.maxX, t.discrete |> Discrete.maxX);
|
||||||
|
|
||||||
let mixedMultiply =
|
let mixedMultiply =
|
||||||
(
|
(
|
||||||
t: DistributionTypes.mixedShape,
|
t: DistributionTypes.mixedShape,
|
||||||
|
@ -197,10 +231,6 @@ module Mixed = {
|
||||||
| _ => None
|
| _ => None
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
//Do the math to add these distributions together
|
|
||||||
// let integral =
|
|
||||||
// (x: float, t: DistributionTypes.mixedShape): option(XYShape.t) => {
|
|
||||||
// };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module Any = {
|
module Any = {
|
||||||
|
@ -223,6 +253,20 @@ module Any = {
|
||||||
Continuous.findIntegralY(x, 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)
|
||||||
|
};
|
||||||
|
|
||||||
// TODO: This is wrong. The discrete component should be made continuous when integrating.
|
// TODO: This is wrong. The discrete component should be made continuous when integrating.
|
||||||
let pdfToCdf = (t: t) =>
|
let pdfToCdf = (t: t) =>
|
||||||
switch (t) {
|
switch (t) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user