diff --git a/showcase/entries/Continuous.re b/showcase/entries/Continuous.re index 741d1ddc..16a377b3 100644 --- a/showcase/entries/Continuous.re +++ b/showcase/entries/Continuous.re @@ -2,7 +2,7 @@ let timeDist = GenericDistribution.make( ~generationSource= - GuesstimatorString("mm(floor(normal(30,3)), normal(39,1), [.5,.5])"), + GuesstimatorString("mm(floor(normal(30,2)), normal(39,1), [.5,.5])"), ~probabilityType=Pdf, ~domain=Complete, ~unit=TimeDistribution({zero: MomentRe.momentNow(), unit: `days}), diff --git a/src/components/charts/ComplexPowerChart.re b/src/components/charts/ComplexPowerChart.re index 9f80d8eb..191847ff 100644 --- a/src/components/charts/ComplexPowerChart.re +++ b/src/components/charts/ComplexPowerChart.re @@ -23,6 +23,37 @@ module ComplexPowerChart = { }; }; +let bar: DistributionTypes.xyShape = { + ys: [|0.5, 0.8, 0.4, 1.0, 2.0|], + xs: [|0.0, 1., 2., 5., 8.|], +}; + +module IntegralChart = { + [@react.component] + let make = (~complexPower: DistributionTypes.complexPower, ~onHover) => { + open DistFunctor.ComplexPower; + let integral = + DistFunctor.ComplexPower.T.Integral.get(~cache=None, complexPower); + let continuous = + integral + |> T.toContinuous + |> E.O.fmap(DistFunctor.Continuous.toLinear) + |> E.O.fmap(DistFunctor.Continuous.getShape); + let minX = T.minX(integral); + let maxX = T.maxX(integral); + let timeScale = + complexPower.unit |> DistributionTypes.DistributionUnit.toJson; + ; + }; +}; + [@react.component] let make = (~complexPower: DistributionTypes.complexPower) => { let (x, setX) = React.useState(() => 0.); @@ -31,8 +62,14 @@ let make = (~complexPower: DistributionTypes.complexPower) => { () => { {setX(_ => r)}} />}, [|complexPower|], ); + let chart2 = + React.useMemo1( + () => { {setX(_ => r)}} />}, + [|complexPower|], + );
chart + chart2 diff --git a/src/core/DistFunctor.re b/src/core/DistFunctor.re index 4fc802cb..7a1fe17a 100644 --- a/src/core/DistFunctor.re +++ b/src/core/DistFunctor.re @@ -77,18 +77,28 @@ module Continuous = { : option(DistributionTypes.continuousShape) => fn(xyShape) |> E.O.fmap(xyShape => make(xyShape, interpolation)); + let toLinear = (t: t): t => + switch (t) { + | {interpolation: `Stepwise, xyShape} => { + interpolation: `Linear, + xyShape: xyShape |> XYShape.Range.stepsToContinuous |> E.O.toExt(""), + } + | {interpolation: `Linear, _} => t + }; + module T = Dist({ type t = DistributionTypes.continuousShape; type integral = DistributionTypes.continuousShape; let shapeFn = (fn, t: t) => t |> xyShape |> fn; + // TODO: Obviously fix this, it's terrible let integral = (~cache, t) => cache |> E.O.default( t |> xyShape |> XYShape.Range.integrateWithTriangles - |> E.O.toExt("") + |> E.O.toExt("Error1") |> fromShape, ); // This seems wrong, we really want the ending bit, I'd assume @@ -118,7 +128,16 @@ module Discrete = { type integral = DistributionTypes.continuousShape; let integral = (~cache, t) => cache - |> E.O.default(t |> XYShape.accumulateYs |> Continuous.fromShape); + |> E.O.default( + { + Continuous.make( + XYShape.accumulateYs(t) + |> XYShape.Range.stepsToContinuous + |> E.O.toExt("ERROR"), + `Stepwise, + ); + }, + ); let integralSum = (~cache, t) => t |> XYShape.ySum; let minX = XYShape.minX; let maxX = XYShape.maxX; @@ -197,26 +216,42 @@ module Mixed = { DistributionTypes.MixedPoint.add(c, d); }; - let toScaledContinuous = - ({continuous, discreteProbabilityMassFraction}: t) => - Some( - continuous - |> Continuous.T.scaleBy( - ~scale=1.0 -. discreteProbabilityMassFraction, - ), - ); + let scaleContinuous = + ({discreteProbabilityMassFraction}: t, continuous) => + continuous + |> Continuous.T.scaleBy(~scale=1.0 -. discreteProbabilityMassFraction); - let toScaledDiscrete = ({discrete, discreteProbabilityMassFraction}: t) => - Some( - discrete - |> Discrete.T.scaleBy(~scale=discreteProbabilityMassFraction), - ); + let scaleDiscrete = ({discreteProbabilityMassFraction}: t, disrete) => + disrete |> Discrete.T.scaleBy(~scale=discreteProbabilityMassFraction); + + let toScaledContinuous = ({continuous} as t: t) => + Some(scaleContinuous(t, continuous)); + + let toScaledDiscrete = ({discrete} as t: t) => + Some(scaleDiscrete(t, discrete)); // TODO: Add these two directly, once interpolation is added. - let integral = (~cache, t) => { - // let cont = scaledContinuousComponent(t); - // let discrete = scaledDiscreteComponent(t); - cache |> E.O.toExt(""); + let integral = + ( + ~cache, + {continuous, discrete, discreteProbabilityMassFraction} as t: t, + ) => { + cache + |> E.O.default( + { + let cont = + continuous + |> Continuous.T.Integral.get(~cache=None) + |> scaleContinuous(t); + let dist = + discrete + |> Discrete.T.Integral.get(~cache=None) + |> Continuous.T.scaleBy( + ~scale=discreteProbabilityMassFraction, + ); + dist; + }, + ); }; let integralSum = @@ -323,7 +358,7 @@ module Shape = { ); let minX = (t: t) => mapToAll(t, (Mixed.T.minX, Discrete.T.minX, Continuous.T.minX)); - let integral = (~cache, t: t) => + let integral = (~cache, t: t) => { mapToAll( t, ( @@ -332,6 +367,7 @@ module Shape = { Continuous.T.Integral.get(~cache), ), ); + }; let integralSum = (~cache, t: t) => mapToAll( t, diff --git a/src/core/DistributionTypes.re b/src/core/DistributionTypes.re index 0cf2a0da..6eda94ee 100644 --- a/src/core/DistributionTypes.re +++ b/src/core/DistributionTypes.re @@ -14,6 +14,11 @@ type xyShape = { ys: array(float), }; +let foo = {xs: [|1., 2., 5.|], ys: [|1., 2., 3.|]}; +let answer = {xs: [|1., 2., 2., 5., 5.|], ys: [|1., 1., 2., 2., 3.|]}; + +let toStepwise = (xyShape: xyShape) => {}; + type interpolationMethod = [ | `Stepwise | `Linear]; type continuousShape = { diff --git a/src/core/GenericDistribution.re b/src/core/GenericDistribution.re index f2c734a6..2603a1cf 100644 --- a/src/core/GenericDistribution.re +++ b/src/core/GenericDistribution.re @@ -15,8 +15,7 @@ let make = unit, }; -let toComplexPower = - (~sampleCount, t: genericDistribution): option(complexPower) => { +let toComplexPower = (~sampleCount, t: genericDistribution) => { let shape = switch (t.generationSource) { | GuesstimatorString(s) => diff --git a/src/core/XYShape.re b/src/core/XYShape.re index 3b6196f9..8da043ca 100644 --- a/src/core/XYShape.re +++ b/src/core/XYShape.re @@ -19,8 +19,24 @@ 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 fromArray = ((xs, ys)): t => {xs, ys}; +let fromArrays = (xs, ys): t => {xs, ys}; let pointwiseMap = (fn, t: t): t => {xs: t.xs, ys: t.ys |> E.A.fmap(fn)}; +let intersperce = (t1: t, t2: t) => { + let foo: ref(array((float, float))) = ref([||]); + let t1 = zip(t1); + let t2 = zip(t2); + + Belt.Array.forEachWithIndex(t1, (i, item) => { + switch (Belt.Array.get(t2, i)) { + | Some(r) => foo := E.A.append(foo^, [|item, r|]) + | None => foo := E.A.append(foo^, [|item|]) + } + }); + foo^ |> Belt.Array.unzip |> fromArray; +}; + let scaleCdfTo = (~scaleTo=1., t: t) => switch (_lastElement(t.ys)) { | Some(n) => @@ -35,9 +51,6 @@ let yFold = (fn, t: t) => { 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)) { @@ -68,6 +81,12 @@ module Range = { let rangeAreaAssumingSteps = (((lastX, lastY), (nextX, _)): zippedRange) => (nextX -. lastX) *. lastY; + let rangePointAssumingSteps = + (((lastX, lastY), (nextX, nextY)): zippedRange) => ( + nextX, + lastY, + ); + let rangeAreaAssumingTriangles = (((lastX, lastY), (nextX, nextY)): zippedRange) => (nextX -. lastX) *. (lastY +. nextY) /. 2.; @@ -93,6 +112,15 @@ module Range = { |> E.O.fmap(accumulateYs); let derivative = mapYsBasedOnRanges(delta_y_over_delta_x); + + let stepsToContinuous = t => + Belt.Array.zip(t.xs, t.ys) + |> E.A.toRanges + |> E.R.toOption + |> E.O.fmap(r => r |> Belt.Array.map(_, rangePointAssumingSteps)) + |> E.O.fmap(Belt.Array.unzip) + |> E.O.fmap(fromArray) + |> E.O.fmap(intersperce(t)); }; let findY = CdfLibrary.Distribution.findY;