Desparately trying to work for many conditions

This commit is contained in:
Ozzie Gooen 2020-02-24 21:01:29 +00:00
parent 3182067a48
commit 8c625a6803
14 changed files with 270 additions and 95 deletions

View File

@ -3,8 +3,12 @@ open Expect;
let shape: DistTypes.xyShape = {xs: [|1., 4., 8.|], ys: [|8., 9., 2.|]}; let shape: DistTypes.xyShape = {xs: [|1., 4., 8.|], ys: [|8., 9., 2.|]};
let makeTest = (str, item1, item2) => let makeTest = (~only=false, str, item1, item2) =>
test(str, () => only
? Only.test(str, () =>
expect(item1) |> toEqual(item2)
)
: test(str, () =>
expect(item1) |> toEqual(item2) expect(item1) |> toEqual(item2)
); );
@ -77,12 +81,20 @@ describe("Shape", () => {
{ {
let continuous = let continuous =
make({xs: [|1., 4., 8.|], ys: [|0.1, 5., 1.0|]}, `Stepwise); make({xs: [|1., 4., 8.|], ys: [|0.1, 5., 1.0|]}, `Stepwise);
continuous |> toLinear |> getShape; continuous |> toLinear |> E.O.fmap(getShape);
}, },
Some({
xs: [|1.00007, 1.00007, 4.0, 4.00007, 8.0, 8.00007|],
ys: [|0.0, 0.1, 0.1, 5.0, 5.0, 1.0|],
}),
);
makeTest(
"toLinear",
{ {
xs: [|1.00007, 4.0, 4.00007, 8.0, 8.00007|], let continuous = make({xs: [|0.0|], ys: [|0.3|]}, `Stepwise);
ys: [|0.1, 0.1, 5.0, 5.0, 1.0|], continuous |> toLinear |> E.O.fmap(getShape);
}, },
Some({xs: [|0.0|], ys: [|0.3|]}),
); );
makeTest( makeTest(
"integralXToY", "integralXToY",
@ -99,7 +111,13 @@ describe("Shape", () => {
T.Integral.xToY(~cache=None, 100.0, continuous), T.Integral.xToY(~cache=None, 100.0, continuous),
47.5, 47.5,
); );
makeTest("integralSum", T.Integral.sum(~cache=None, continuous), 47.5); makeTest(
"integralEndY",
continuous
|> T.scaleToIntegralSum(~intendedSum=1.0)
|> T.Integral.sum(~cache=None),
1.0,
);
}); });
describe("Discrete", () => { describe("Discrete", () => {
@ -166,7 +184,7 @@ describe("Shape", () => {
T.Integral.xToY(~cache=None, 6.0, discrete), T.Integral.xToY(~cache=None, 6.0, discrete),
0.9, 0.9,
); );
makeTest("integralSum", T.Integral.sum(~cache=None, discrete), 1.0); makeTest("integralEndY", T.Integral.sum(~cache=None, discrete), 1.0);
}); });
describe("Mixed", () => { describe("Mixed", () => {
@ -229,6 +247,7 @@ describe("Shape", () => {
T.xToY(7., mixed), T.xToY(7., mixed),
{discrete: 0.0, continuous: 0.04095904095904096}, {discrete: 0.0, continuous: 0.04095904095904096},
); );
makeTest("integralEndY", T.Integral.sum(~cache=None, mixed), 1.0);
makeTest( makeTest(
"scaleBy", "scaleBy",
T.scaleBy(~scale=2.0, mixed), T.scaleBy(~scale=2.0, mixed),
@ -254,9 +273,10 @@ describe("Shape", () => {
T.Integral.get(~cache=None, mixed), T.Integral.get(~cache=None, mixed),
Distributions.Continuous.make( Distributions.Continuous.make(
{ {
xs: [|1.00007, 3., 4., 4.00007, 7., 8., 8.00007, 14.|], xs: [|1.00007, 1.00007, 3., 4., 4.00007, 7., 8., 8.00007, 14.|],
ys: [| ys: [|
0.15, 0.0,
0.0,
0.15, 0.15,
0.18496503496503497, 0.18496503496503497,
0.4349674825174825, 0.4349674825174825,
@ -270,4 +290,76 @@ describe("Shape", () => {
), ),
); );
}); });
describe("Mixed", () => {
open Distributions.DistPlus;
let discrete: DistTypes.xyShape = {
xs: [|1., 4., 8.|],
ys: [|0.3, 0.5, 0.2|],
};
let continuous =
Distributions.Continuous.make(
{xs: [|3., 7., 14.|], ys: [|0.058, 0.082, 0.124|]},
`Linear,
)
|> Distributions.Continuous.T.scaleToIntegralSum(~intendedSum=1.0);
let mixed =
MixedShapeBuilder.build(
~continuous,
~discrete,
~assumptions={
continuous: ADDS_TO_CORRECT_PROBABILITY,
discrete: ADDS_TO_CORRECT_PROBABILITY,
discreteProbabilityMass: Some(0.5),
},
)
|> E.O.toExn("");
let distPlus =
Distributions.DistPlus.make(
~shape=Mixed(mixed),
~guesstimatorString=None,
(),
);
makeTest("minX", T.minX(distPlus), Some(1.0));
makeTest("maxX", T.maxX(distPlus), Some(14.0));
makeTest(
"xToY at 4.0",
T.xToY(4., distPlus),
{discrete: 0.25, continuous: 0.03196803196803197},
);
makeTest(
"xToY at 0.0",
T.xToY(0., distPlus),
{discrete: 0.0, continuous: 0.028971028971028972},
);
makeTest(
"xToY at 5.0",
T.xToY(7., distPlus),
{discrete: 0.0, continuous: 0.04095904095904096},
);
makeTest("integralEndY", T.Integral.sum(~cache=None, distPlus), 1.0);
makeTest(
"integral",
T.Integral.get(~cache=None, distPlus) |> T.toContinuous,
Some(
Distributions.Continuous.make(
{
xs: [|1.00007, 1.00007, 3., 4., 4.00007, 7., 8., 8.00007, 14.|],
ys: [|
0.0,
0.0,
0.15,
0.18496503496503497,
0.4349674825174825,
0.5398601398601399,
0.5913086913086913,
0.6913122927072927,
1.0,
|],
},
`Linear,
),
),
);
});
}); });

View File

@ -1,12 +1,18 @@
// "mm(floor(uniform(30,35)), normal(50,20), [.25,.5])", // "mm(floor(uniform(30,35)), normal(50,20), [.25,.5])",
// "mm(floor(normal(28,4)), normal(32,2), uniform(20,24), [.5,.2,.1])",
let timeVector: TimeTypes.timeVector = {
zero: MomentRe.momentNow(),
unit: `years,
};
let timeDist = let timeDist =
DistPlusIngredients.make( DistPlusIngredients.make(
~guesstimatorString="mm(floor(normal(30,2)), normal(39,1), [.5,.5])", ~guesstimatorString="mm(floor(10 to 15), 10 to 11, [.9,.1])",
~domain=Complete, ~domain=Complete,
~unit=TimeDistribution({zero: MomentRe.momentNow(), unit: `days}), ~unit=DistTypes.TimeDistribution(timeVector),
(), (),
) )
|> DistPlusIngredients.toDistPlus(~sampleCount=1000); |> DistPlusIngredients.toDistPlus(~sampleCount=5000, ~outputXYPoints=1000);
let distributions = () => let distributions = () =>
<div> <div>

View File

@ -103,9 +103,16 @@ let make = (~distPlus: DistTypes.distPlus) => {
|> E.Float.with2DigitsPrecision |> E.Float.with2DigitsPrecision
|> ReasonReact.string} |> ReasonReact.string}
</th> </th>
<th className="px-4 py-2 border ">
{distPlus
|> Distributions.DistPlus.T.Integral.sum(~cache=None)
|> E.Float.with2DigitsPrecision
|> ReasonReact.string}
</th>
</tr> </tr>
</tbody> </tbody>
</table> </table>
<div /> <div />
</div>; </div>;
// chart
}; };

View File

@ -320,7 +320,7 @@ export class CdfChartD3 {
function mouseover() { function mouseover() {
const mouse = d3.mouse(this); const mouse = d3.mouse(this);
hoverLine.attr('opacity', 1).attr('x1', mouse[0]).attr('x2', mouse[0]); hoverLine.attr('opacity', 1).attr('x1', mouse[0]).attr('x2', mouse[0]);
const xValue = xScale.invert(mouse[0]).toFixed(2); const xValue = xScale.invert(mouse[0]);
// This used to be here, but doesn't seem important // This used to be here, but doesn't seem important
// const xValue = (mouse[0] > range[0] && mouse[0] < range[1]) ? : 0; // const xValue = (mouse[0] > range[0] && mouse[0] < range[1]) ? : 0;
context.attrs.onHover(xValue); context.attrs.onHover(xValue);

View File

@ -8,22 +8,27 @@ let make =
unit, unit,
}; };
let toDistPlus = (~sampleCount, t: distPlusIngredients): option(distPlus) => { let toDistPlus =
(~sampleCount=1000, ~outputXYPoints=1000, t: distPlusIngredients)
: option(distPlus) => {
let shape = let shape =
Guesstimator.stringToMixedShape( Guesstimator.stringToMixedShape(
~string=t.guesstimatorString, ~string=t.guesstimatorString,
~sampleCount, ~sampleCount,
~outputXYPoints,
(), (),
) );
|> E.O.bind(_, Distributions.Mixed.clean); Js.log2("Line 21 with shape:", shape);
let ss =
shape shape
|> E.O.fmap(shape => |> E.O.fmap(
Distributions.DistPlus.make( Distributions.DistPlus.make(
~shape, ~shape=_,
~domain=t.domain, ~domain=t.domain,
~unit=t.unit, ~unit=t.unit,
~guesstimatorString=None, ~guesstimatorString=None,
(), (),
) ),
); );
ss;
}; };

View File

@ -80,7 +80,7 @@ module DistributionUnit = {
module Domain = { module Domain = {
let excludedProbabilityMass = (t: domain) => { let excludedProbabilityMass = (t: domain) => {
switch (t) { switch (t) {
| Complete => 1.0 | Complete => 0.0
| LeftLimited({excludingProbabilityMass}) => excludingProbabilityMass | LeftLimited({excludingProbabilityMass}) => excludingProbabilityMass
| RightLimited({excludingProbabilityMass}) => excludingProbabilityMass | RightLimited({excludingProbabilityMass}) => excludingProbabilityMass
| LeftAndRightLimited( | LeftAndRightLimited(

View File

@ -28,7 +28,7 @@ module type dist = {
type integral; type integral;
let integral: (~cache: option(integral), t) => integral; let integral: (~cache: option(integral), t) => integral;
let integralSum: (~cache: option(integral), t) => float; let integralEndY: (~cache: option(integral), t) => float;
let integralXtoY: (~cache: option(integral), float, t) => float; let integralXtoY: (~cache: option(integral), float, t) => float;
}; };
@ -37,6 +37,11 @@ module Dist = (T: dist) => {
type integral = T.integral; type integral = T.integral;
let minX = T.minX; let minX = T.minX;
let maxX = T.maxX; let maxX = T.maxX;
let xTotalRange = (t: t) =>
switch (minX(t), maxX(t)) {
| (Some(min), Some(max)) => Some(max -. min)
| _ => None
};
let pointwiseFmap = T.pointwiseFmap; let pointwiseFmap = T.pointwiseFmap;
let xToY = T.xToY; let xToY = T.xToY;
let toShape = T.toShape; let toShape = T.toShape;
@ -51,7 +56,7 @@ module Dist = (T: dist) => {
type t = T.integral; type t = T.integral;
let get = T.integral; let get = T.integral;
let xToY = T.integralXtoY; let xToY = T.integralXtoY;
let sum = T.integralSum; let sum = T.integralEndY;
}; };
// This is suboptimal because it could get the cache but doesn't here. // This is suboptimal because it could get the cache but doesn't here.
@ -78,20 +83,24 @@ module Continuous = {
(fn, {xyShape, interpolation}: t): option(DistTypes.continuousShape) => (fn, {xyShape, interpolation}: t): option(DistTypes.continuousShape) =>
fn(xyShape) |> E.O.fmap(make(_, interpolation)); fn(xyShape) |> E.O.fmap(make(_, interpolation));
let toLinear = (t: t): t => let toLinear = (t: t): option(t) => {
switch (t) { switch (t) {
| {interpolation: `Stepwise, xyShape} => { | {interpolation: `Stepwise, xyShape} =>
interpolation: `Linear, xyShape
xyShape: xyShape |> XYShape.Range.stepsToContinuous |> E.O.toExt(""), |> XYShape.Range.stepsToContinuous
} |> E.O.fmap(xyShape => make(xyShape, `Linear))
| {interpolation: `Linear, _} => t | {interpolation: `Linear, _} => Some(t)
}; };
};
let shapeFn = (fn, t: t) => t |> xyShape |> fn;
let convertToNewLength = i =>
shapeMap(CdfLibrary.Distribution.convertToNewLength(i));
module T = module T =
Dist({ Dist({
type t = DistTypes.continuousShape; type t = DistTypes.continuousShape;
type integral = DistTypes.continuousShape; type integral = DistTypes.continuousShape;
let shapeFn = (fn, t: t) => t |> xyShape |> fn;
let minX = shapeFn(XYShape.minX); let minX = shapeFn(XYShape.minX);
let maxX = shapeFn(XYShape.maxX); let maxX = shapeFn(XYShape.maxX);
let pointwiseFmap = (fn, t: t) => let pointwiseFmap = (fn, t: t) =>
@ -126,7 +135,7 @@ module Continuous = {
|> E.O.toExt("This should not have happened") |> E.O.toExt("This should not have happened")
|> fromShape, |> fromShape,
); );
let integralSum = (~cache, t) => t |> integral(~cache) |> lastY; let integralEndY = (~cache, t) => t |> integral(~cache) |> lastY;
let integralXtoY = (~cache, f, t) => let integralXtoY = (~cache, f, t) =>
t |> integral(~cache) |> shapeFn(CdfLibrary.Distribution.findY(f)); t |> integral(~cache) |> shapeFn(CdfLibrary.Distribution.findY(f));
let toContinuous = t => Some(t); let toContinuous = t => Some(t);
@ -144,7 +153,7 @@ module Discrete = {
let integral = (~cache, t) => let integral = (~cache, t) =>
cache cache
|> E.O.default(Continuous.make(XYShape.accumulateYs(t), `Stepwise)); |> E.O.default(Continuous.make(XYShape.accumulateYs(t), `Stepwise));
let integralSum = (~cache, t) => let integralEndY = (~cache, t) =>
t |> integral(~cache) |> Continuous.lastY; t |> integral(~cache) |> Continuous.lastY;
let minX = XYShape.minX; let minX = XYShape.minX;
let maxX = XYShape.maxX; let maxX = XYShape.maxX;
@ -186,8 +195,6 @@ module Mixed = {
discrete: {xs: [||], ys: [||]}, discrete: {xs: [||], ys: [||]},
} => } =>
None None
| {continuous, discrete: {xs: [|_|], ys: [|_|]}} =>
Some(Continuous(continuous))
| {continuous, discrete: {xs: [||], ys: [||]}} => | {continuous, discrete: {xs: [||], ys: [||]}} =>
Some(Continuous(continuous)) Some(Continuous(continuous))
| {continuous: {xyShape: {xs: [||], ys: [||]}}, discrete} => | {continuous: {xyShape: {xs: [||], ys: [||]}}, discrete} =>
@ -241,7 +248,6 @@ module Mixed = {
let toScaledDiscrete = ({discrete} as t: t) => let toScaledDiscrete = ({discrete} as t: t) =>
Some(scaleDiscrete(t, discrete)); Some(scaleDiscrete(t, discrete));
// TODO: Add these two directly, once interpolation is added.
let integral = let integral =
( (
~cache, ~cache,
@ -258,6 +264,7 @@ module Mixed = {
discrete discrete
|> Discrete.T.Integral.get(~cache=None) |> Discrete.T.Integral.get(~cache=None)
|> Continuous.toLinear |> Continuous.toLinear
|> E.O.toExn("")
|> Continuous.T.scaleBy( |> Continuous.T.scaleBy(
~scale=discreteProbabilityMassFraction, ~scale=discreteProbabilityMassFraction,
); );
@ -274,17 +281,8 @@ module Mixed = {
); );
}; };
// todo: Get last element of actual sum. let integralEndY = (~cache, t: t) => {
let integralSum = (~cache, {discrete, continuous} as t: t) => { integral(~cache, t) |> Continuous.lastY;
switch (cache) {
| Some(cache) => 3.0
| None =>
scaleDiscreteFn(t, Discrete.T.Integral.sum(~cache=None, discrete))
+. scaleContinuousFn(
t,
Continuous.T.Integral.sum(~cache=None, continuous),
)
};
}; };
let integralXtoY = (~cache, f, {discrete, continuous} as t: t) => { let integralXtoY = (~cache, f, {discrete, continuous} as t: t) => {
@ -381,7 +379,7 @@ module Shape = {
), ),
); );
}; };
let integralSum = (~cache, t: t) => let integralEndY = (~cache, t: t) =>
mapToAll( mapToAll(
t, t,
( (
@ -419,6 +417,7 @@ module DistPlus = {
type t = DistTypes.distPlus; type t = DistTypes.distPlus;
let shapeIntegral = shape => Shape.T.Integral.get(~cache=None, shape);
let make = let make =
( (
~shape, ~shape,
@ -428,7 +427,7 @@ module DistPlus = {
(), (),
) )
: t => { : t => {
let integral = Shape.T.Integral.get(~cache=None, shape); let integral = shapeIntegral(shape);
{shape, domain, integralCache: integral, unit, guesstimatorString}; {shape, domain, integralCache: integral, unit, guesstimatorString};
}; };
@ -448,6 +447,11 @@ module DistPlus = {
guesstimatorString: E.O.default(t.guesstimatorString, guesstimatorString), guesstimatorString: E.O.default(t.guesstimatorString, guesstimatorString),
}; };
let updateShape = (shape, t) => {
let integralCache = shapeIntegral(shape);
update(~shape, ~integralCache, t);
};
let domainIncludedProbabilityMass = (t: t) => let domainIncludedProbabilityMass = (t: t) =>
Domain.includedProbabilityMass(t.domain); Domain.includedProbabilityMass(t.domain);
@ -499,15 +503,15 @@ module DistPlus = {
let maxX = shapeFn(Shape.T.maxX); let maxX = shapeFn(Shape.T.maxX);
let fromShape = (t, shape): t => update(~shape, t); let fromShape = (t, shape): t => update(~shape, t);
// todo: adjust for limit, maybe?
let pointwiseFmap = (fn, {shape, _} as t: t): t =>
Shape.T.pointwiseFmap(fn, shape) |> fromShape(t);
// This bit is kind of akward, could probably use rethinking. // This bit is kind of akward, could probably use rethinking.
let integral = (~cache as _, t: t) => let integral = (~cache as _, t: t) =>
fromShape(t, Continuous(t.integralCache)); updateShape(Continuous(t.integralCache), t);
let integralSum = (~cache as _, t: t) => // todo: adjust for limit, maybe?
let pointwiseFmap = (fn, {shape, _} as t: t): t =>
Shape.T.pointwiseFmap(fn, shape) |> updateShape(_, t);
let integralEndY = (~cache as _, t: t) =>
Shape.T.Integral.sum(~cache=Some(t.integralCache), toShape(t)); Shape.T.Integral.sum(~cache=Some(t.integralCache), toShape(t));
// TODO: Fix this below, obviously. Adjust for limits // TODO: Fix this below, obviously. Adjust for limits

View File

@ -8,6 +8,29 @@ type assumptions = {
discreteProbabilityMass: option(float), discreteProbabilityMass: option(float),
}; };
let buildSimple = (~continuous, ~discrete): option(DistTypes.shape) => {
let cLength =
continuous |> Distributions.Continuous.getShape |> XYShape.xs |> E.A.length;
let dLength = discrete |> XYShape.xs |> E.A.length;
switch (cLength, dLength) {
| (0 | 1, 0) => None
| (0 | 1, _) => Some(Discrete(discrete))
| (_, 0) => Some(Continuous(continuous))
| (_, _) =>
let discreteProbabilityMassFraction =
Distributions.Discrete.T.Integral.sum(~cache=None, discrete);
let discrete =
Distributions.Discrete.T.scaleToIntegralSum(~intendedSum=1.0, discrete);
let foobar =
Distributions.Mixed.make(
~continuous,
~discrete,
~discreteProbabilityMassFraction,
)
|> Distributions.Mixed.clean;
foobar;
};
};
let build = (~continuous, ~discrete, ~assumptions) => let build = (~continuous, ~discrete, ~assumptions) =>
switch (assumptions) { switch (assumptions) {
| { | {

View File

@ -47,8 +47,9 @@ module XtoY = {
let stepwiseIncremental = (f, t: t) => let stepwiseIncremental = (f, t: t) =>
firstPairAtOrBeforeValue(f, t) |> E.O.fmap(((_, y)) => y); firstPairAtOrBeforeValue(f, t) |> E.O.fmap(((_, y)) => y);
let stepwiseIfAtX = (f, t: t) => let stepwiseIfAtX = (f: float, t: t) => {
getBy(t, ((x, _)) => x == f) |> E.O.fmap(((_, y)) => y); getBy(t, ((x: float, _)) => {x == f}) |> E.O.fmap(((_, y)) => y);
};
// TODO: When Roman's PR comes in, fix this bit. This depends on interpolation, obviously. // TODO: When Roman's PR comes in, fix this bit. This depends on interpolation, obviously.
let linear = (f, t: t) => t |> CdfLibrary.Distribution.findY(f); let linear = (f, t: t) => t |> CdfLibrary.Distribution.findY(f);
@ -208,6 +209,7 @@ module Range = {
// TODO: It would be nicer if this the diff didn't change the first element, and also maybe if there were a more elegant way of doing this. // TODO: It would be nicer if this the diff didn't change the first element, and also maybe if there were a more elegant way of doing this.
let stepsToContinuous = t => { let stepsToContinuous = t => {
let diff = xTotalRange(t) |> E.O.fmap(r => r *. 0.00001); let diff = xTotalRange(t) |> E.O.fmap(r => r *. 0.00001);
let items =
switch (diff, E.A.toRanges(Belt.Array.zip(t.xs, t.ys))) { switch (diff, E.A.toRanges(Belt.Array.zip(t.xs, t.ys))) {
| (Some(diff), Ok(items)) => | (Some(diff), Ok(items)) =>
Some( Some(
@ -217,7 +219,18 @@ module Range = {
|> fromArray |> fromArray
|> intersperce(t |> xMap(e => e +. diff)), |> intersperce(t |> xMap(e => e +. diff)),
) )
| _ => Some(t)
};
let bar = items |> E.O.fmap(zip) |> E.O.bind(_, E.A.get(_, 0));
let items =
switch (items, bar) {
| (Some(items), Some((0.0, _))) => Some(items)
| (Some(items), Some((firstX, _))) =>
let all = E.A.append([|(firstX, 0.0)|], items |> zip);
let foo = all |> Belt.Array.unzip |> fromArray;
Some(foo);
| _ => None | _ => None
}; };
items;
}; };
}; };

View File

@ -151,7 +151,8 @@ module Model = {
| Some({truthValue: false}) => difference | Some({truthValue: false}) => difference
| None => | None =>
let foo = let foo =
getGlobalCatastropheChance(dateTime) // getGlobalCatastropheChance(dateTime)
Some(0.5)
|> E.O.fmap(E.Float.with2DigitsPrecision) |> E.O.fmap(E.Float.with2DigitsPrecision)
|> E.O.fmap((r: string) => |> E.O.fmap((r: string) =>
"uniform(0,1) > " ++ r ++ " ? " ++ difference ++ ": 0" "uniform(0,1) > " ++ r ++ " ? " ++ difference ++ ": 0"
@ -177,7 +178,6 @@ module Model = {
GuesstimatorDist.logNormal(40., 4.), GuesstimatorDist.logNormal(40., 4.),
), ),
~domain=RightLimited({xPoint: 100., excludingProbabilityMass: 0.3}), ~domain=RightLimited({xPoint: 100., excludingProbabilityMass: 0.3}),
~unit=TimeDistribution({zero: currentDateTime, unit: `years}),
(), (),
), ),
) )

View File

@ -97,6 +97,18 @@ const {
return cdf.findY(x); return cdf.findY(x);
} }
/**
*
* @param x
* @param xs
* @param ys
* @returns {number[]}
*/
function convertToNewLength(n, { xs, ys }) {
let dist = new ContinuousDistribution(xs, ys);
return dist.convertToNewLength(n);
}
/** /**
* *
* @param y * @param y
@ -153,6 +165,7 @@ const {
pdfToCdf, pdfToCdf,
findY, findY,
findX, findX,
convertToNewLength,
mean, mean,
scoreNonMarketCdfCdf, scoreNonMarketCdfCdf,
differentialEntropy, differentialEntropy,

View File

@ -32,9 +32,18 @@ module JS = {
[@bs.module "./CdfLibrary.js"] [@bs.module "./CdfLibrary.js"]
external differentialEntropy: (int, distJs) => distJs = external differentialEntropy: (int, distJs) => distJs =
"differentialEntropy"; "differentialEntropy";
[@bs.module "./CdfLibrary.js"]
external convertToNewLength: (int, distJs) => distJs = "convertToNewLength";
}; };
module Distribution = { module Distribution = {
let convertToNewLength = (int, {xs, _} as dist: DistTypes.xyShape) =>
switch (E.A.length(xs)) {
| 0
| 1 => dist
| _ => dist |> JS.doAsDist(JS.convertToNewLength(int))
};
let toPdf = dist => dist |> JS.doAsDist(JS.cdfToPdf); let toPdf = dist => dist |> JS.doAsDist(JS.cdfToPdf);
let toCdf = dist => dist |> JS.doAsDist(JS.pdfToCdf); let toCdf = dist => dist |> JS.doAsDist(JS.pdfToCdf);
let findX = (y, dist) => dist |> JS.distToJs |> JS.findX(y); let findX = (y, dist) => dist |> JS.distToJs |> JS.findX(y);

View File

@ -16,6 +16,7 @@ module Internals = {
discrete, discrete,
}; };
// todo: Force to be fewer samples
let toContinous = (r: combined) => let toContinous = (r: combined) =>
continuousGet(r) continuousGet(r)
|> CdfLibrary.JS.jsToDist |> CdfLibrary.JS.jsToDist
@ -25,22 +26,24 @@ module Internals = {
discreteGet(r) |> jsToDistDiscrete; discreteGet(r) |> jsToDistDiscrete;
[@bs.module "./GuesstimatorLibrary.js"] [@bs.module "./GuesstimatorLibrary.js"]
external toCombinedFormat: (string, int) => combined = "run"; external toCombinedFormat: (string, int, int) => combined = "run";
// todo: Format to correct mass, also normalize the pdf. // todo: Format to correct mass, also normalize the pdf.
let toMixedShape = (r: combined): option(DistTypes.mixedShape) => { let toMixedShape = (r: combined): option(DistTypes.shape) => {
let assumptions: MixedShapeBuilder.assumptions = { let continuous =
continuous: ADDS_TO_1, toContinous(r) |> Distributions.Continuous.convertToNewLength(100);
discrete: ADDS_TO_CORRECT_PROBABILITY, let discrete = toDiscrete(r);
discreteProbabilityMass: None, // let continuousProb =
}; // cont |> Distributions.Continuous.T.Integral.sum(~cache=None);
MixedShapeBuilder.build( // let discreteProb =
~continuous=toContinous(r), // d |> Distributions.Discrete.T.Integral.sum(~cache=None);
~discrete=toDiscrete(r),
~assumptions, let foo = MixedShapeBuilder.buildSimple(~continuous, ~discrete);
); foo;
}; };
}; };
let stringToMixedShape = (~string, ~sampleCount=1000, ()) => let stringToMixedShape =
Internals.toCombinedFormat(string, sampleCount) |> Internals.toMixedShape; (~string, ~sampleCount=1000, ~outputXYPoints=1000, ()) =>
Internals.toCombinedFormat(string, sampleCount, outputXYPoints)
|> Internals.toMixedShape;

View File

@ -34,7 +34,7 @@ const ratioSize = samples => {
}; };
const toPdf = (values, sampleCount, min, max) => { const toPdf = (values, outputResolutionCount, min, max) => {
let duplicateSamples = _(values).groupBy().pickBy(x => x.length > 1).keys().value(); let duplicateSamples = _(values).groupBy().pickBy(x => x.length > 1).keys().value();
let totalLength = _.size(values); let totalLength = _.size(values);
let frequencies = duplicateSamples.map(s => ({value: parseFloat(s), percentage: _(values).filter(x => x ==s).size()/totalLength})); let frequencies = duplicateSamples.map(s => ({value: parseFloat(s), percentage: _(values).filter(x => x ==s).size()/totalLength}));
@ -48,13 +48,13 @@ const toPdf = (values, sampleCount, min, max) => {
const ratioSize$ = ratioSize(samples); const ratioSize$ = ratioSize(samples);
const width = ratioSize$ === 'SMALL' ? 100 : 1; const width = ratioSize$ === 'SMALL' ? 100 : 1;
const pdf = samples.toPdf({ size: sampleCount, width, min, max }); const pdf = samples.toPdf({ size: outputResolutionCount, width, min, max });
continuous = pdf; continuous = pdf;
} }
return {continuous, discrete}; return {continuous, discrete};
}; };
let run = (text, sampleCount, inputs=[], min=false, max=false) => { let run = (text, sampleCount, outputResolutionCount, inputs=[], min=false, max=false) => {
let [_error, item] = Guesstimator.parse({ text: "=" + text }); let [_error, item] = Guesstimator.parse({ text: "=" + text });
const { parsedInput } = item; const { parsedInput } = item;
const { guesstimateType } = parsedInput; const { guesstimateType } = parsedInput;
@ -78,7 +78,7 @@ let run = (text, sampleCount, inputs=[], min=false, max=false) => {
} else if (values.length === 1) { } else if (values.length === 1) {
update = blankResponse; update = blankResponse;
} else { } else {
update = toPdf(values, sampleCount, min, max); update = toPdf(values, outputResolutionCount, min, max);
} }
return update; return update;
} }