diff --git a/src/TimeLimitedDomainCdf.re b/src/TimeLimitedDomainCdf.re index f19067b9..4c763957 100644 --- a/src/TimeLimitedDomainCdf.re +++ b/src/TimeLimitedDomainCdf.re @@ -1,62 +1,4 @@ -type timeUnit = [ - | `days - | `hours - | `milliseconds - | `minutes - | `months - | `quarters - | `seconds - | `weeks - | `years -]; - -type timeVector = { - zero: MomentRe.Moment.t, - unit: timeUnit, -}; - -type timePoint = { - timeVector, - value: float, -}; - -module TimePoint = { - let fromTimeVector = (timeVector, value): timePoint => {timeVector, value}; - - let toMoment = (timePoint: timePoint) => { - timePoint.timeVector.zero - |> MomentRe.Moment.add( - ~duration= - MomentRe.duration(timePoint.value, timePoint.timeVector.unit), - ); - }; - - let fromMoment = (timeVector: timeVector, moment: MomentRe.Moment.t) => - MomentRe.diff(timeVector.zero, moment, timeVector.unit); -}; - -module RelativeTimePoint = { - type timeInVector = - | Time(MomentRe.Moment.t) - | XValue(float); - - let toTime = (timeVector: timeVector, timeInVector: timeInVector) => - switch (timeInVector) { - | Time(r) => r - | XValue(r) => - timeVector.zero - |> MomentRe.Moment.add(~duration=MomentRe.duration(r, timeVector.unit)) - }; - - let _timeToX = (time, timeStart, timeUnit) => - MomentRe.diff(timeStart, time, timeUnit); - - let toXValue = (timeVector: timeVector, timeInVector: timeInVector) => - switch (timeInVector) { - | Time(r) => _timeToX(r, timeVector.zero, timeVector.unit) - | XValue(r) => r - }; -}; +open TimeTypes; type t = { timeVector, diff --git a/src/lib/DistributionTypes.re b/src/lib/DistributionTypes.re new file mode 100644 index 00000000..6c568f15 --- /dev/null +++ b/src/lib/DistributionTypes.re @@ -0,0 +1,136 @@ +type domainLimit = { + xPoint: float, + excludingProbabilityMass: float, +}; + +type domain = + | Complete + | LeftLimited(domainLimit) + | RightLimited(domainLimit) + | LeftAndRightLimited(domainLimit, domainLimit); + +type continuousShape = { + xs: array(float), + ys: array(float), +}; + +type discreteShape = { + xs: array(float), + ys: array(float), +}; + +type mixedShape = { + continuous: continuousShape, + discrete: discreteShape, + discreteProbabilityMassFraction: float, +}; + +type pointsType = + | Mixed(mixedShape) + | Discrete(discreteShape) + | Continuous(continuousShape); + +type generationSource = + | GuesstimatorString(string) + | Shape(pointsType); + +type distributionUnit = + | Unspecified + | Time(TimeTypes.timeVector); + +type probabilityType = + | Cdf + | Pdf + | Arbitrary; + +type genericDistribution = { + generationSource, + probabilityType, + domain, + unit: distributionUnit, +}; + +module Shape = { + module Continuous = { + let fromArrays = (xs, ys): continuousShape => {xs, ys}; + }; + + module Discrete = { + let fromArrays = (xs, ys): continuousShape => {xs, ys}; + }; + + module Mixed = { + let make = (~continuous, ~discrete, ~discreteProbabilityMassFraction) => { + continuous, + discrete, + discreteProbabilityMassFraction, + }; + + module Builder = { + type assumption = + | ADDS_TO_1 + | ADDS_TO_CORRECT_PROBABILITY; + type assumptions = { + continuous: assumption, + discrete: assumption, + discreteProbabilityMass: option(float), + }; + let build = (~continuous, ~discrete, ~assumptions) => + switch (assumptions) { + | { + continuous: ADDS_TO_CORRECT_PROBABILITY, + discrete: ADDS_TO_CORRECT_PROBABILITY, + discreteProbabilityMass: Some(r), + } => + // TODO: Fix this, it's wrong :( + Some( + make(~continuous, ~discrete, ~discreteProbabilityMassFraction=r), + ) + | { + continuous: ADDS_TO_1, + discrete: ADDS_TO_1, + discreteProbabilityMass: Some(r), + } => + Some( + make(~continuous, ~discrete, ~discreteProbabilityMassFraction=r), + ) + | { + continuous: ADDS_TO_1, + discrete: ADDS_TO_1, + discreteProbabilityMass: None, + } => + None + | { + continuous: ADDS_TO_CORRECT_PROBABILITY, + discrete: ADDS_TO_1, + discreteProbabilityMass: None, + } => + None + | { + continuous: ADDS_TO_1, + discrete: ADDS_TO_CORRECT_PROBABILITY, + discreteProbabilityMass: None, + } => + None + | _ => None + }; + }; + }; +}; + +module GenericDistribution = { + let make = + ( + ~generationSource, + ~probabilityType=Pdf, + ~domain=Complete, + ~unit=Unspecified, + (), + ) + : genericDistribution => { + generationSource, + probabilityType, + domain, + unit, + }; +}; \ No newline at end of file diff --git a/src/lib/Prop.re b/src/lib/Prop.re index 54841316..51582f27 100644 --- a/src/lib/Prop.re +++ b/src/lib/Prop.re @@ -55,41 +55,41 @@ module Value = { | SelectSingle(r) => r |> ReasonReact.string | ConditionalArray(r) => "Array" |> ReasonReact.string | Conditional(r) => r.name |> ReasonReact.string - | TimeLimitedDomainCdfLazy(r) => - let timeLimited = r(CdfLibrary.Distribution.fromString(_, 1000)); - let cdf = timeLimited.limitedDomainCdf.distribution; - <> - Types.ContinuousDistribution.toJs} /> - CdfLibrary.Distribution.toPdf - |> Types.ContinuousDistribution.toJs - } - /> - {FloatCdf.logNormal(50., 20.) |> ReasonReact.string} - ; + | TimeLimitedDomainCdfLazy(r) =>
+ // let timeLimited = r(CdfLibrary.Distribution.fromString(_, 1000)); + // let cdf = timeLimited.limitedDomainCdf.distribution; + // <> + // Types.ContinuousDistribution.toJs} /> + // CdfLibrary.Distribution.toPdf + // |> Types.ContinuousDistribution.toJs + // } + // /> + // {FloatCdf.logNormal(50., 20.) |> ReasonReact.string} + // ; | TimeLimitedDomainCdf(r) => let cdf: Types.ContinuousDistribution.t = r.limitedDomainCdf.distribution; <> Types.ContinuousDistribution.toJs} /> ; - | FloatCdf(r) => - let cdf: Types.ContinuousDistribution.t = - CdfLibrary.Distribution.fromString(r, 2000); - <> - CdfLibrary.Distribution.toPdf - |> Types.ContinuousDistribution.toJs - } - /> - {r |> ReasonReact.string} - ; + | FloatCdf(r) =>
+ // let cdf: Types.MixedDistribution.t = + // CdfLibrary.Distribution.fromString(r, 2000); + // <> + // CdfLibrary.Distribution.toPdf + // |> Types.ContinuousDistribution.toJs + // } + // /> + // {r |> ReasonReact.string} + // ; | Probability(r) => (r *. 100. |> Js.Float.toFixed) ++ "%" |> ReasonReact.string | DateTime(r) => r |> MomentRe.Moment.defaultFormat |> ReasonReact.string diff --git a/src/lib/TimeTypes.re b/src/lib/TimeTypes.re new file mode 100644 index 00000000..db08c5bd --- /dev/null +++ b/src/lib/TimeTypes.re @@ -0,0 +1,59 @@ +type timeUnit = [ + | `days + | `hours + | `milliseconds + | `minutes + | `months + | `quarters + | `seconds + | `weeks + | `years +]; + +type timeVector = { + zero: MomentRe.Moment.t, + unit: timeUnit, +}; + +type timePoint = { + timeVector, + value: float, +}; + +module TimePoint = { + let fromTimeVector = (timeVector, value): timePoint => {timeVector, value}; + + let toMoment = (timePoint: timePoint) => { + timePoint.timeVector.zero + |> MomentRe.Moment.add( + ~duration= + MomentRe.duration(timePoint.value, timePoint.timeVector.unit), + ); + }; + + let fromMoment = (timeVector: timeVector, moment: MomentRe.Moment.t) => + MomentRe.diff(timeVector.zero, moment, timeVector.unit); +}; + +module RelativeTimePoint = { + type timeInVector = + | Time(MomentRe.Moment.t) + | XValue(float); + + let toTime = (timeVector: timeVector, timeInVector: timeInVector) => + switch (timeInVector) { + | Time(r) => r + | XValue(r) => + timeVector.zero + |> MomentRe.Moment.add(~duration=MomentRe.duration(r, timeVector.unit)) + }; + + let _timeToX = (time, timeStart, timeUnit) => + MomentRe.diff(timeStart, time, timeUnit); + + let toXValue = (timeVector: timeVector, timeInVector: timeInVector) => + switch (timeInVector) { + | Time(r) => _timeToX(r, timeVector.zero, timeVector.unit) + | XValue(r) => r + }; +}; \ No newline at end of file diff --git a/src/lib/Types.re b/src/lib/Types.re index 81eea880..dffde0f1 100644 --- a/src/lib/Types.re +++ b/src/lib/Types.re @@ -59,7 +59,7 @@ module DiscreteDistribution = { }; module MixedDistribution = { - type distribution = { + type t = { discrete: DiscreteDistribution.t, continuous: ContinuousDistribution.t, }; diff --git a/src/utility/CdfLibrary.re b/src/utility/CdfLibrary.re index 1bcf4c37..59b1796c 100644 --- a/src/utility/CdfLibrary.re +++ b/src/utility/CdfLibrary.re @@ -39,8 +39,35 @@ module JS = { external scoreNonMarketCdfCdf: (int, distJs, distJs, float) => distJs = "scoreNonMarketCdfCdf"; - [@bs.module "./GuesstimatorLibrary.js"] - external toGuesstimator: (string, int) => distJs = "run"; + module Guesstimator = { + [@bs.deriving abstract] + type discrete = { + xs: array(float), + ys: array(float), + }; + + let jsToDistDiscrete = (d: discrete): Types.DiscreteDistribution.t => { + xs: xsGet(d), + ys: ysGet(d), + }; + + [@bs.deriving abstract] + type combined = { + continuous: distJs, + discrete, + }; + + let toContinous = (r: combined) => continuousGet(r) |> jsToDist; + let toDiscrete = (r: combined): Types.DiscreteDistribution.t => + discreteGet(r) |> jsToDistDiscrete; + let toMixed = (r: combined): Types.MixedDistribution.t => { + discrete: toDiscrete(r), + continuous: toContinous(r), + }; + + [@bs.module "./GuesstimatorLibrary.js"] + external toGuesstimator: (string, int) => combined = "run"; + }; }; module Distribution = { @@ -49,7 +76,8 @@ module Distribution = { let findX = (y, dist) => dist |> JS.distToJs |> JS.findX(y); let findY = (x, dist) => dist |> JS.distToJs |> JS.findY(x); let fromString = (str: string, sampleCount: int) => - JS.toGuesstimator(str, sampleCount) |> JS.jsToDist; + JS.Guesstimator.toGuesstimator(str, sampleCount) + |> JS.Guesstimator.toMixed; let integral = dist => dist |> JS.distToJs |> JS.integral; let differentialEntropy = (maxCalculationLength, dist) => dist diff --git a/src/utility/GuesstimatorLibrary.js b/src/utility/GuesstimatorLibrary.js index 345ceb77..cc9f1012 100644 --- a/src/utility/GuesstimatorLibrary.js +++ b/src/utility/GuesstimatorLibrary.js @@ -33,14 +33,19 @@ const ratioSize = samples => { return minMaxRatio(minValue, maxValue); }; + const toPdf = (values, sampleCount, min, max) => { - const samples = new Samples(values); + let duplicateSamples = _(values).groupBy().pickBy(x => x.length > 1).keys().value(); + let totalLength = _.size(values); + let frequencies = duplicateSamples.map(s => ({value: parseFloat(s), percentage: totalLength/_(values).filter(x => x ==s).size()})); + let continuousSamples = _.difference(values, frequencies.map(f => f.value)); + const samples = new Samples(continuousSamples); const ratioSize$ = ratioSize(samples); const width = ratioSize$ === 'SMALL' ? 20 : 1; const cdf = samples.toCdf({ size: sampleCount, width, min, max }); - return {ys:cdf.ys, xs:cdf.xs}; + return {continuous:{ys:cdf.ys, xs:cdf.xs}, discrete: {xs: frequencies.map(f => f.value), ys: frequencies.map(f => f.percentage)}}; }; let run = (text, sampleCount, inputs=[], min=false, max=false) => {