From c30fab22c74f88a1f45e1bd4ad4c084d1c6cc8f3 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Tue, 25 Feb 2020 19:27:30 +0000 Subject: [PATCH] Fixed math around fixed integral calculations --- showcase/entries/Continuous.re | 5 ++- src/components/charts/DistPlusPlot.re | 21 ++++----- src/distributions/DistPlusIngredients.re | 4 +- src/distributions/DistTypes.re | 2 +- src/distributions/Distributions.re | 54 +++++++++++++++++------- src/models/EAFunds.re | 18 ++------ 6 files changed, 56 insertions(+), 48 deletions(-) diff --git a/showcase/entries/Continuous.re b/showcase/entries/Continuous.re index 1d4baeb5..f0a9b7d8 100644 --- a/showcase/entries/Continuous.re +++ b/showcase/entries/Continuous.re @@ -4,7 +4,7 @@ let timeDist = DistPlusIngredients.make( ~guesstimatorString="(floor(10 to 15))", - ~domain=Complete, + ~domain=RightLimited({xPoint: 50.0, excludingProbabilityMass: 0.3}), ~unit= DistTypes.TimeDistribution({zero: MomentRe.momentNow(), unit: `years}), (), @@ -25,7 +25,8 @@ let distributions = () => {setup( DistPlusIngredients.make( ~guesstimatorString="mm(5 to 20, floor(normal(20,2)), [.5, .5])", - ~domain=Complete, + ~domain= + RightLimited({xPoint: 50.0, excludingProbabilityMass: 0.3}), (), ), ) diff --git a/src/components/charts/DistPlusPlot.re b/src/components/charts/DistPlusPlot.re index c7975bca..e60062e3 100644 --- a/src/components/charts/DistPlusPlot.re +++ b/src/components/charts/DistPlusPlot.re @@ -2,11 +2,10 @@ module DistPlusChart = { [@react.component] let make = (~distPlus: DistTypes.distPlus, ~onHover) => { open Distributions.DistPlus; - // todo: Change to scaledContinuous and scaledDiscrete - let discrete = distPlus |> T.toDiscrete; + let discrete = distPlus |> T.toScaledDiscrete; let continuous = distPlus - |> T.toContinuous + |> T.toScaledContinuous |> E.O.fmap(Distributions.Continuous.getShape); let minX = T.minX(distPlus); let maxX = T.maxX(distPlus); @@ -40,6 +39,7 @@ module IntegralChart = { { |> E.Float.with2DigitsPrecision |> ReasonReact.string} + + {distPlus + |> Distributions.DistPlus.T.Integral.sum(~cache=None) + |> E.Float.with2DigitsPrecision + |> ReasonReact.string} + - @@ -132,12 +135,6 @@ let make = (~distPlus: DistTypes.distPlus) => { -
- {"Y Integral Total" |> ReasonReact.string} - {"Continuous Total" |> ReasonReact.string}
- {distPlus - |> Distributions.DistPlus.T.Integral.sum(~cache=None) - |> E.Float.with2DigitsPrecision - |> ReasonReact.string} - {distPlus |> Distributions.DistPlus.T.toContinuous diff --git a/src/distributions/DistPlusIngredients.re b/src/distributions/DistPlusIngredients.re index 6431059c..9882b917 100644 --- a/src/distributions/DistPlusIngredients.re +++ b/src/distributions/DistPlusIngredients.re @@ -11,8 +11,8 @@ let make = let toDistPlus = ( ~sampleCount=2000, - ~outputXYPoints=2000, - ~truncateTo=Some(100), + ~outputXYPoints=1500, + ~truncateTo=Some(300), t: distPlusIngredients, ) : option(distPlus) => { diff --git a/src/distributions/DistTypes.re b/src/distributions/DistTypes.re index d970a824..3ce13e1d 100644 --- a/src/distributions/DistTypes.re +++ b/src/distributions/DistTypes.re @@ -120,7 +120,7 @@ module MixedPoint = { let makeContinuous = (continuous: float): t => {continuous, discrete: 0.0}; let makeDiscrete = (discrete: float): t => {continuous: 0.0, discrete}; - let fmap = (fn, t: t) => { + let fmap = (fn: float => float, t: t) => { continuous: fn(t.continuous), discrete: fn(t.discrete), }; diff --git a/src/distributions/Distributions.re b/src/distributions/Distributions.re index 61aa25fe..6afd2e06 100644 --- a/src/distributions/Distributions.re +++ b/src/distributions/Distributions.re @@ -202,10 +202,15 @@ module Mixed = { let scaleContinuous = ({discreteProbabilityMassFraction}: t, continuous) => continuous - |> Continuous.T.scaleBy(~scale=1.0 -. discreteProbabilityMassFraction); + |> Continuous.T.scaleToIntegralSum( + ~intendedSum=1.0 -. discreteProbabilityMassFraction, + ); let scaleDiscrete = ({discreteProbabilityMassFraction}: t, disrete) => - disrete |> Discrete.T.scaleBy(~scale=discreteProbabilityMassFraction); + disrete + |> Discrete.T.scaleToIntegralSum( + ~intendedSum=discreteProbabilityMassFraction, + ); module T = Dist({ @@ -239,28 +244,46 @@ module Mixed = { let integral = ( ~cache, - {continuous, discrete, discreteProbabilityMassFraction} as t: t, + {continuous, discrete, discreteProbabilityMassFraction}: t, ) => { switch (cache) { | Some(cache) => cache | None => + let scaleContinuousBy = + (1.0 -. discreteProbabilityMassFraction) + /. (continuous |> Continuous.T.Integral.sum(~cache=None)); + + let scaleDiscreteBy = + discreteProbabilityMassFraction + /. ( + discrete + |> Discrete.T.Integral.get(~cache=None) + |> Continuous.toLinear + |> E.O.fmap(Continuous.lastY) + |> E.O.toExn("") + ); + let cont = continuous |> Continuous.T.Integral.get(~cache=None) - |> scaleContinuous(t); + |> Continuous.T.scaleBy(~scale=scaleContinuousBy); + let dist = discrete |> Discrete.T.Integral.get(~cache=None) |> Continuous.toLinear |> E.O.toExn("") - |> Continuous.T.scaleBy(~scale=discreteProbabilityMassFraction); - Continuous.make( - XYShape.Combine.combineLinear( - Continuous.getShape(cont), Continuous.getShape(dist), (a, b) => - a +. b - ), - `Linear, - ); + |> Continuous.T.scaleBy(~scale=scaleDiscreteBy); + + let result = + Continuous.make( + XYShape.Combine.combineLinear( + Continuous.getShape(cont), Continuous.getShape(dist), (a, b) => + a +. b + ), + `Linear, + ); + result; }; }; @@ -484,7 +507,6 @@ module DistPlus = { let minX = shapeFn(Shape.T.minX); let maxX = shapeFn(Shape.T.maxX); - let fromShape = (t, shape): t => update(~shape, t); // This bit is kind of akward, could probably use rethinking. let integral = (~cache, t: t) => @@ -499,14 +521,14 @@ module DistPlus = { // TODO: Fix this below, obviously. Adjust for limits let integralXtoY = (~cache as _, f, t: t) => { - Shape.T.Integral.xToY(~cache=Some(t.integralCache), f, toShape(t)); + Shape.T.Integral.xToY(~cache=Some(t.integralCache), f, toShape(t)) + |> domainIncludedProbabilityMassAdjustment(t); }; }); }; module DistPlusTime = { open DistTypes; - open DistPlus; type t = DistTypes.distPlus; @@ -529,7 +551,7 @@ module DistPlusTime = { module Integral = { include DistPlus.T.Integral; - let xToY = (~cache as _, f: TimeTypes.timeInVector, t: t) => { + let xToY = (f: TimeTypes.timeInVector, t: t) => { timeInVectorToX(f, t) |> E.O.fmap(x => DistPlus.T.Integral.xToY(~cache=None, x, t)); }; diff --git a/src/models/EAFunds.re b/src/models/EAFunds.re index 1dd3a3df..c15f4726 100644 --- a/src/models/EAFunds.re +++ b/src/models/EAFunds.re @@ -110,19 +110,8 @@ module Model = { // TODO: Fixe number that integral is calculated for let getGlobalCatastropheChance = dateTime => { GlobalCatastrophe.makeI(MomentRe.momentNow()) - |> DistPlusIngredients.toDistPlus(~sampleCount=1000) - |> E.O.bind( - _, - t => { - let foo = - Distributions.DistPlusTime.Integral.xToY( - ~cache=None, - Time(dateTime), - t, - ); - Some(0.5); - }, - ); + |> DistPlusIngredients.toDistPlus + |> E.O.bind(_, Distributions.DistPlusTime.Integral.xToY(Time(dateTime))); }; let make = @@ -151,8 +140,7 @@ module Model = { | Some({truthValue: false}) => difference | None => let foo = - // getGlobalCatastropheChance(dateTime) - Some(0.5) + getGlobalCatastropheChance(dateTime) |> E.O.fmap(E.Float.with2DigitsPrecision) |> E.O.fmap((r: string) => "uniform(0,1) > " ++ r ++ " ? " ++ difference ++ ": 0"