diff --git a/package.json b/package.json index f08e139c..19fec304 100644 --- a/package.json +++ b/package.json @@ -51,8 +51,8 @@ "moduleserve": "0.9.1", "moment": "2.24.0", "parcel-bundler": "1.12.4", + "parcel-plugin-bundle-visualiser": "^1.2.0", "parcel-plugin-less-js-enabled": "1.0.2", - "parcel-plugin-bundle-visualiser": "1.2.0", "pdfast": "^0.2.0", "postcss-cli": "7.1.0", "rationale": "0.2.0", diff --git a/src/distPlus/distribution/Distributions.re b/src/distPlus/distribution/Distributions.re index 4d03d46d..0148c91a 100644 --- a/src/distPlus/distribution/Distributions.re +++ b/src/distPlus/distribution/Distributions.re @@ -24,6 +24,7 @@ module Dist = (T: dist) => { type integral = T.integral; let minX = T.minX; let maxX = T.maxX; + let integral = T.integral; let xTotalRange = (t: t) => maxX(t) -. minX(t); let mapY = T.mapY; let xToY = T.xToY; @@ -244,6 +245,7 @@ module Mixed = { let toContinuous = ({continuous}: t) => Some(continuous); let toDiscrete = ({discrete}: t) => Some(discrete); let toDiscreteProbabilityMass = ({discreteProbabilityMassFraction}: t) => discreteProbabilityMassFraction; + let xToY = (f, {discrete, continuous} as t: t) => { let c = continuous diff --git a/src/distPlus/renderers/ShapeRenderer.re b/src/distPlus/renderers/ShapeRenderer.re index 7c346135..5b668999 100644 --- a/src/distPlus/renderers/ShapeRenderer.re +++ b/src/distPlus/renderers/ShapeRenderer.re @@ -1,15 +1,36 @@ -let runSymbolic = - (guesstimatorString, length) =>{ - let graph = MathJsParser.fromString(guesstimatorString); - graph |> E.R.fmap(g => RenderTypes.ShapeRenderer.Symbolic.make(g, SymbolicDist.toShape(length,g))) - } - +// This transforms an array intesperced with spaces or newlines with a normally formatted one. +// "3 4 5 3 2 1 " -> "[3,4,5,3,2,1]"" +let formatMessyArray = str => { + let split = Js.String.splitByRe([%re "/\\n|\\r|\\s/"], str); + if (E.A.length(split) > 6) { + let inner = split |> Js.Array.joinWith(","); + {j|[$inner]|j}; + } else { + str; + }; +}; + +let formatString = str => { + str |> formatMessyArray; +}; + +let runSymbolic = (guesstimatorString, length) => { + let str = formatString(guesstimatorString); + let graph = MathJsParser.fromString(str); + graph + |> E.R.fmap(g => + RenderTypes.ShapeRenderer.Symbolic.make( + g, + SymbolicDist.toShape(length, g), + ) + ); +}; + let run = - ( - inputs: RenderTypes.ShapeRenderer.Combined.inputs - ) + (inputs: RenderTypes.ShapeRenderer.Combined.inputs) : RenderTypes.ShapeRenderer.Combined.outputs => { - let symbolic = runSymbolic(inputs.guesstimatorString, inputs.symbolicInputs.length); + let symbolic = + runSymbolic(inputs.guesstimatorString, inputs.symbolicInputs.length); let sampling = switch (symbolic) { | Ok(_) => None diff --git a/src/distPlus/renderers/samplesRenderer/Samples.re b/src/distPlus/renderers/samplesRenderer/Samples.re index cb48c1b5..7318a9dd 100644 --- a/src/distPlus/renderers/samplesRenderer/Samples.re +++ b/src/distPlus/renderers/samplesRenderer/Samples.re @@ -107,7 +107,11 @@ module T = { }; let toShape = - (~samples: t, ~samplingInputs: RenderTypes.ShapeRenderer.Sampling.Inputs.fInputs, ()) => { + ( + ~samples: t, + ~samplingInputs: RenderTypes.ShapeRenderer.Sampling.Inputs.fInputs, + (), + ) => { Array.fast_sort(compare, samples); let (continuousPart, discretePart) = E.A.Sorted.Floats.split(samples); let length = samples |> E.A.length |> float_of_int; @@ -161,6 +165,16 @@ module T = { samplesParse; }; + let fromSamples = + ( + ~samplingInputs=RenderTypes.ShapeRenderer.Sampling.Inputs.empty, + samples, + ) => { + let samplingInputs = + RenderTypes.ShapeRenderer.Sampling.Inputs.toF(samplingInputs); + toShape(~samples, ~samplingInputs, ()); + }; + let fromGuesstimatorString = ( ~guesstimatorString, @@ -169,13 +183,17 @@ module T = { ) => { let hasValidSamples = Guesstimator.stringToSamples(guesstimatorString, 10) |> E.A.length > 0; - let samplingInputs = RenderTypes.ShapeRenderer.Sampling.Inputs.toF(samplingInputs); + let _samplingInputs = + RenderTypes.ShapeRenderer.Sampling.Inputs.toF(samplingInputs); switch (hasValidSamples) { | false => None | true => let samples = - Guesstimator.stringToSamples(guesstimatorString, samplingInputs.sampleCount); - Some(toShape(~samples, ~samplingInputs, ())); + Guesstimator.stringToSamples( + guesstimatorString, + _samplingInputs.sampleCount, + ); + Some(fromSamples(~samplingInputs, samples)); }; }; }; \ No newline at end of file diff --git a/src/distPlus/symbolic/MathJsParser.re b/src/distPlus/symbolic/MathJsParser.re index 5144d221..d0ec5a59 100644 --- a/src/distPlus/symbolic/MathJsParser.re +++ b/src/distPlus/symbolic/MathJsParser.re @@ -177,6 +177,28 @@ module MathAdtToDistDst = { }; }; + let arrayParser = (args:array(arg)):result(SymbolicDist.bigDist, string) => { + let samples = args + |> E.A.fmap( + fun + | Value(n) => Some(n) + | _ => None + ) + |> E.A.O.concatSomes + let outputs = Samples.T.fromSamples(samples); + let pdf = outputs.shape |> E.O.bind(_,Distributions.Shape.T.toContinuous) + let shape = pdf |> E.O.fmap(pdf => { + let _pdf = Distributions.Continuous.T.scaleToIntegralSum(~cache=None, ~intendedSum=1.0, pdf); + let cdf = Distributions.Continuous.T.integral(~cache=None, _pdf); + SymbolicDist.ContinuousShape.make(_pdf, cdf) + }) + switch(shape){ + | Some(s) => Ok(`Simple(`ContinuousShape(s))) + | None => Error("Rendering did not work") + } + } + + let rec functionParser = (r): result(SymbolicDist.bigDist, string) => r |> ( @@ -228,7 +250,7 @@ module MathAdtToDistDst = { fun | Fn(_) => functionParser(r) | Value(r) => Ok(`Simple(`Float(r))) - | Array(_) => Error("Array not valid as top level") + | Array(r) => arrayParser(r) | Symbol(_) => Error("Symbol not valid as top level") | Object(_) => Error("Object not valid as top level") ); diff --git a/src/distPlus/symbolic/SymbolicDist.re b/src/distPlus/symbolic/SymbolicDist.re index cec8e1d6..1fdec0d5 100644 --- a/src/distPlus/symbolic/SymbolicDist.re +++ b/src/distPlus/symbolic/SymbolicDist.re @@ -31,6 +31,8 @@ type triangular = { high: float, }; +type continuousShape = {pdf: DistTypes.continuousShape, cdf: DistTypes.continuousShape} + type contType = [ | `Continuous | `Discrete]; type dist = [ @@ -41,6 +43,7 @@ type dist = [ | `Exponential(exponential) | `Cauchy(cauchy) | `Triangular(triangular) + | `ContinuousShape(continuousShape) | `Float(float) ]; @@ -48,6 +51,17 @@ type pointwiseAdd = array((dist, float)); type bigDist = [ | `Simple(dist) | `PointwiseCombination(pointwiseAdd)]; +module ContinuousShape = { + type t = continuousShape; + let make = (pdf, cdf):t => ({pdf, cdf}); + let pdf = (x, t: t) => Distributions.Continuous.T.xToY(x,t.pdf).continuous + let inv = (p, t: t) => Distributions.Continuous.T.xToY(p,t.pdf).continuous + // TODO: Fix the sampling, to have it work correctly. + let sample = (t:t) => 3.0; + let toString = (t) => {j|CustomContinuousShape|j}; + let contType: contType = `Continuous; +}; + module Exponential = { type t = exponential; let pdf = (x, t: t) => Jstat.exponential##pdf(x, t.rate); @@ -153,6 +167,7 @@ module GenericSimple = { | `Uniform(n) => Uniform.pdf(x, n) | `Beta(n) => Beta.pdf(x, n) | `Float(n) => Float.pdf(x, n) + | `ContinuousShape(n) => ContinuousShape.pdf(x,n) }; let contType = (dist:dist):contType => @@ -165,6 +180,7 @@ module GenericSimple = { | `Uniform(_) => Uniform.contType | `Beta(_) => Beta.contType | `Float(_) => Float.contType + | `ContinuousShape(_) => ContinuousShape.contType }; let inv = (x, dist) => @@ -177,6 +193,7 @@ module GenericSimple = { | `Uniform(n) => Uniform.inv(x, n) | `Beta(n) => Beta.inv(x, n) | `Float(n) => Float.inv(x, n) + | `ContinuousShape(n) => ContinuousShape.inv(x,n) }; let sample: dist => float = @@ -188,7 +205,8 @@ module GenericSimple = { | `Lognormal(n) => Lognormal.sample(n) | `Uniform(n) => Uniform.sample(n) | `Beta(n) => Beta.sample(n) - | `Float(n) => Float.sample(n); + | `Float(n) => Float.sample(n) + | `ContinuousShape(n) => ContinuousShape.sample(n) let toString: dist => string = fun @@ -199,7 +217,8 @@ module GenericSimple = { | `Lognormal(n) => Lognormal.toString(n) | `Uniform(n) => Uniform.toString(n) | `Beta(n) => Beta.toString(n) - | `Float(n) => Float.toString(n); + | `Float(n) => Float.toString(n) + | `ContinuousShape(n) => ContinuousShape.toString(n) let min: dist => float = fun @@ -210,6 +229,7 @@ module GenericSimple = { | `Lognormal(n) => Lognormal.inv(minCdfValue, n) | `Uniform({low}) => low | `Beta(n) => Beta.inv(minCdfValue, n) + | `ContinuousShape(n) => ContinuousShape.inv(minCdfValue,n) | `Float(n) => n; let max: dist => float = @@ -220,6 +240,7 @@ module GenericSimple = { | `Normal(n) => Normal.inv(maxCdfValue, n) | `Lognormal(n) => Lognormal.inv(maxCdfValue, n) | `Beta(n) => Beta.inv(maxCdfValue, n) + | `ContinuousShape(n) => ContinuousShape.inv(maxCdfValue,n) | `Uniform({high}) => high | `Float(n) => n; @@ -236,11 +257,16 @@ module GenericSimple = { let toShape = (~xSelection: [ | `Linear | `ByWeight]=`Linear, dist: dist, sampleCount) : DistTypes.shape => { - let xs = interpolateXs(~xSelection, dist, sampleCount); - let ys = xs |> E.A.fmap(r => pdf(r, dist)); - XYShape.T.fromArrays(xs, ys) - |> Distributions.Continuous.make(`Linear, _) - |> Distributions.Continuous.T.toShape; + switch(dist){ + | `ContinuousShape(n) => n.pdf |> Distributions.Continuous.T.toShape + | dist => { + let xs = interpolateXs(~xSelection, dist, sampleCount); + let ys = xs |> E.A.fmap(r => pdf(r, dist)); + XYShape.T.fromArrays(xs, ys) + |> Distributions.Continuous.make(`Linear, _) + |> Distributions.Continuous.T.toShape; + } + } }; }; diff --git a/yarn.lock b/yarn.lock index 473d4091..336c60d7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2418,11 +2418,6 @@ bser@2.1.1: dependencies: node-int64 "^0.4.0" -btoa@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/btoa/-/btoa-1.2.1.tgz#01a9909f8b2c93f6bf680ba26131eb30f7fa3d73" - integrity sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g== - buffer-equal@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-0.0.1.tgz#91bc74b11ea405bc916bc6aa908faafa5b4aac4b" @@ -3802,11 +3797,6 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= -ejs@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.0.2.tgz#745b01cdcfe38c1c6a2da3bbb2d9957060a31226" - integrity sha512-IncmUpn1yN84hy2shb0POJ80FWrfGNY0cxO9f4v+/sG7qcBvAtVWUA1IdzY/8EYUmOVhoKJVdJjNd3AZcnxOjA== - electron-to-chromium@^1.3.341: version "1.3.345" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.345.tgz#2569d0d54a64ef0f32a4b7e8c80afa5fe57c5d98" @@ -3942,7 +3932,7 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" -escape-html@^1.0.3, escape-html@~1.0.3: +escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= @@ -4469,7 +4459,7 @@ glob-to-regexp@^0.3.0: resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs= -glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: +glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: version "7.1.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== @@ -4559,14 +4549,6 @@ gzip-size@^4.1.0: duplexer "^0.1.1" pify "^3.0.0" -gzip-size@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-5.1.1.tgz#cb9bee692f87c0612b232840a873904e4c135274" - integrity sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA== - dependencies: - duplexer "^0.1.1" - pify "^4.0.1" - hammerjs@^2.0.8: version "2.0.8" resolved "https://registry.yarnpkg.com/hammerjs/-/hammerjs-2.0.8.tgz#04ef77862cff2bb79d30f7692095930222bf60f1" @@ -5050,11 +5032,6 @@ is-directory@^0.3.1: resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE= -is-docker@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.0.0.tgz#2cb0df0e75e2d064fe1864c37cdeacb7b2dcf25b" - integrity sha512-pJEdRugimx4fBMra5z2/5iRdZ63OhYV0vr0Dwm5+xtW4D1FvRkB8hamMIhnWfyJeDdyr/aa7BDyNbtG38VxgoQ== - is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" @@ -6595,14 +6572,6 @@ onetime@^5.1.0: dependencies: mimic-fn "^2.1.0" -open@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/open/-/open-7.0.3.tgz#db551a1af9c7ab4c7af664139930826138531c48" - integrity sha512-sP2ru2v0P290WFfv49Ap8MF6PkzGNnGlAwHweB4WR4mr5d2d0woiCluUeJ218w7/+PmoBy9JmYgD5A4mLcWOFA== - dependencies: - is-docker "^2.0.0" - is-wsl "^2.1.1" - opn@^5.1.0: version "5.5.0" resolved "https://registry.yarnpkg.com/opn/-/opn-5.5.0.tgz#fc7164fab56d235904c51c3b27da6758ca3b9bfc" @@ -6818,7 +6787,7 @@ parcel-bundler@1.12.4, parcel-bundler@^1.12.3: v8-compile-cache "^2.0.0" ws "^5.1.1" -parcel-plugin-bundle-visualiser@1.2.0: +parcel-plugin-bundle-visualiser@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/parcel-plugin-bundle-visualiser/-/parcel-plugin-bundle-visualiser-1.2.0.tgz#b24cde64233c8e8ce2561ec5d864a7543d8e719d" integrity sha512-/O+26nsOwXbl1q6A/X9lEJWAPwZt5VauTV32omC3a/09bfUgHTogkAIYB/BqrGQm6OyuoG5FATToT3AGGk9RTA== @@ -7035,11 +7004,6 @@ pify@^3.0.0: resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= -pify@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" - integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== - pinkie-promise@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" @@ -8640,13 +8604,6 @@ rimraf@^3.0.0: dependencies: glob "^7.1.3" -rimraf@~2.6.2: - version "2.6.3" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== - dependencies: - glob "^7.1.3" - ripemd160@^2.0.0, ripemd160@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" @@ -8975,24 +8932,6 @@ sort-keys@^1.0.0: dependencies: is-plain-obj "^1.0.0" -source-map-explorer@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/source-map-explorer/-/source-map-explorer-2.4.2.tgz#fb23f86c3112eacde5683f24efaf4ddc9f677985" - integrity sha512-3ECQLffCFV8QgrTqcmddLkWL4/aQs6ljYfgWCLselo5QtizOfOeUCKnS4rFn7MIrdeZLM6TZrseOtsrWZhWKoQ== - dependencies: - btoa "^1.2.1" - chalk "^3.0.0" - convert-source-map "^1.7.0" - ejs "^3.0.2" - escape-html "^1.0.3" - glob "^7.1.6" - gzip-size "^5.1.1" - lodash "^4.17.15" - open "^7.0.3" - source-map "^0.7.3" - temp "^0.9.1" - yargs "^15.3.1" - source-map-resolve@^0.5.0: version "0.5.3" resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" @@ -9427,13 +9366,6 @@ tailwindcss@1.2.0: reduce-css-calc "^2.1.6" resolve "^1.14.2" -temp@^0.9.1: - version "0.9.1" - resolved "https://registry.yarnpkg.com/temp/-/temp-0.9.1.tgz#2d666114fafa26966cd4065996d7ceedd4dd4697" - integrity sha512-WMuOgiua1xb5R56lE0eH6ivpVmg/lq2OHm4+LtT/xtEtPQ+sz6N3bBM6WZ5FvO1lO4IKIOb43qnhoc4qxP5OeA== - dependencies: - rimraf "~2.6.2" - terminal-link@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" @@ -10111,14 +10043,6 @@ yargs-parser@^16.1.0: camelcase "^5.0.0" decamelize "^1.2.0" -yargs-parser@^18.1.1: - version "18.1.2" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.2.tgz#2f482bea2136dbde0861683abea7756d30b504f1" - integrity sha512-hlIPNR3IzC1YuL1c2UwwDKpXlNFBqD1Fswwh1khz5+d8Cq/8yc/Mn0i+rQXduu8hcrFKvO7Eryk+09NecTQAAQ== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - yargs-parser@^9.0.2: version "9.0.2" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-9.0.2.tgz#9ccf6a43460fe4ed40a9bb68f48d43b8a68cc077" @@ -10178,23 +10102,6 @@ yargs@^15.0.0, yargs@^15.0.2: y18n "^4.0.0" yargs-parser "^16.1.0" -yargs@^15.3.1: - version "15.3.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.3.1.tgz#9505b472763963e54afe60148ad27a330818e98b" - integrity sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA== - dependencies: - cliui "^6.0.0" - decamelize "^1.2.0" - find-up "^4.1.0" - get-caller-file "^2.0.1" - require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^4.2.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^18.1.1" - zen-observable-ts@^0.8.20: version "0.8.20" resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-0.8.20.tgz#44091e335d3fcbc97f6497e63e7f57d5b516b163"