UNPKG

distriprob

Version:

A library for calculating the PDF, CDFs, and quantile function values of common probability distributions

1,675 lines (1,665 loc) 125 kB
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.distriprob = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ (function (process){ "use strict"; function asyncGen(functionDependencies, script, scriptArgs) { let worker; if (isNode()) { const scriptString = createScriptStr(functionDependencies, script, scriptArgs, true); const Worker = require("webworker-threads").Worker; const functionArg = new Function(scriptString); worker = new Worker(functionArg); } else { const scriptString = createScriptStr(functionDependencies, script, scriptArgs, false); const blobURL = URL.createObjectURL(new Blob([scriptString], { type: "application/javascript" })); worker = new Worker(blobURL); URL.revokeObjectURL(blobURL); } return new Promise((resolve, reject) => { worker.onmessage = function (event) { worker.terminate(); resolve(event.data); }; worker.postMessage("get to work!"); }); } exports.asyncGen = asyncGen; function createScriptStr(functionDependencies, script, scriptArgs, node) { let argString = ""; for (let i = 0; i < scriptArgs.length; i++) { let arg = scriptArgs[i]; if (Array.isArray(arg)) { argString += "[" + arg.toString() + "]"; } else if (arg === null) { argString += "null"; } else if (typeof arg === "string") { argString += `"${arg}"`; } else { argString += arg.toString(); } if (i < (scriptArgs.length - 1)) { argString += ", "; } } let result = ""; for (let funct of functionDependencies) { result += funct.toString() + "\n"; } result += "let result = (" + script.toString() + ")(" + argString + ");\n"; if (node) { result += "self.onmessage = function(event) {\n"; } else { result += "self.onmessage = function(event) {\n"; } result += "postMessage(result);\n"; result += "};\n"; return result; } function isNode() { return typeof process === "object" && process + "" === "[object process]"; } }).call(this,require('_process')) },{"_process":21,"webworker-threads":30}],2:[function(require,module,exports){ "use strict"; const async_1 = require("./async"); const random_1 = require("./random"); const cfs = require("./continuedFractionSolver"); const gamma = require("./gamma"); const rf = require("./rootFind"); // This import and then renaming of imports is necessary to allow the async module to // correctly generate web worker scripts. const lnGamma = gamma.lnGamma; const continuedFractionSolver = cfs.continuedFractionSolver; const rootFind = rf.rootFind; function lnBeta(x, y) { return (lnGamma(x) + lnGamma(y)) - lnGamma(x + y); } exports.lnBeta = lnBeta; /** * a function to calculate the "d_i" values from * http://www.stat.tamu.edu/~jnewton/604/chap3.pdf pp.15-16 * in the calculation of the IB(incomplete beta function) * * @param i - the index of the d_i values * @param x - parameter from the IB function * @param a - parameter from the IB function * @param b - parameter from the IB function * @returns {any} - the d_i value */ function d(i, x, a, b) { var result; var m; if (i % 2 === 0) { m = i / 2; result = (m * (b - m) * x) / ((a + 2 * m - 1) * (a + 2 * m)); } else if (i % 2 === 1) { m = (i - 1) / 2; result = -((a + m) * (a + b + m) * x) / ((a + 2 * m) * (a + 2 * m + 1)); } return result; } exports.d = d; function continuedFraction(x, a, b) { function num(j) { if (j === 1) { return 1; } else { return d(j - 1, x, a, b); } } function denom(j) { if (j === 0) { return 0; } else { return 1; } } return continuedFractionSolver(num, denom); } exports.continuedFraction = continuedFraction; function lnIncompleteBeta(x, a, b) { const comparator = (a + 1) / (a + b + 1); if (x >= comparator) { return Math.log(1 - Math.exp(lnIncompleteBeta(1 - x, b, a))); } const alnx = a * Math.log(x); const bln1MinusX = b * Math.log(1 - x); const lna = Math.log(a); const lnBetaAB = lnBeta(a, b); const lnContinuedFraction = Math.log(continuedFraction(x, a, b)); return alnx + bln1MinusX - lna - lnBetaAB + lnContinuedFraction; } exports.lnIncompleteBeta = lnIncompleteBeta; function incompleteBeta(x, a, b) { return Math.exp(lnIncompleteBeta(x, a, b)); } exports.incompleteBeta = incompleteBeta; function inverseIncompleteBeta(p, a, b) { const lnIncompBeta = function (x) { return lnIncompleteBeta(x, a, b); }; const derivativeLnIncompleteBeta = function (x) { const lnBetaAB = lnBeta(a, b); const lnIncBetaXAB = lnIncompleteBeta(x, a, b); const bMinus1TimesLn1MinusX = (b - 1) * Math.log(1 - x); const aMinus1TimesLnX = (a - 1) * Math.log(x); return Math.exp(bMinus1TimesLn1MinusX + aMinus1TimesLnX - lnBetaAB - lnIncBetaXAB); }; return rootFind(lnIncompBeta, derivativeLnIncompleteBeta, Math.log(p), 0.5, 1, 0); } exports.inverseIncompleteBeta = inverseIncompleteBeta; function pdfSync(x, alpha, beta) { if (x < 0 || x > 1) { return 0; } else { return Math.exp(((alpha - 1) * Math.log(x)) + ((beta - 1) * Math.log(1 - x)) - lnBeta(alpha, beta)); } } exports.pdfSync = pdfSync; function pdf(x, alpha, beta) { return async_1.asyncGen([lnGamma, lnBeta], pdfSync, [x, alpha, beta]); } exports.pdf = pdf; function cdfSync(x, alpha, beta, lowerTail = true) { if (x <= 0) { if (lowerTail) { return 0; } else { return 1; } } else if (x >= 1) { if (lowerTail) { return 1; } else { return 0; } } else { if (lowerTail) { return incompleteBeta(x, alpha, beta); } else { return incompleteBeta(1 - x, beta, alpha); } } } exports.cdfSync = cdfSync; function cdf(x, alpha, beta, lowerTail = true) { return async_1.asyncGen([ lnBeta, lnGamma, continuedFractionSolver, d, continuedFraction, lnIncompleteBeta, incompleteBeta ], cdfSync, [x, alpha, beta, lowerTail]); } exports.cdf = cdf; function quantileSync(p, alpha, beta, lowerTail = true) { function f(val) { return cdfSync(val, alpha, beta, lowerTail); } function fPrime(val) { if (lowerTail) { return pdfSync(val, alpha, beta); } else { return -pdfSync(val, alpha, beta); } } const mean = alpha / (alpha + beta); if (p === 0) { if (lowerTail) { return 0; } else { return 1; } } else if (p === 1) { if (lowerTail) { return 1; } else { return 0; } } else { return rootFind(f, fPrime, p, mean, 1, 0); } } exports.quantileSync = quantileSync; function quantile(x, alpha, beta, lowerTail = true) { return async_1.asyncGen([ rf.newton, rf.bisection, rootFind, lnBeta, lnGamma, continuedFractionSolver, d, continuedFraction, lnIncompleteBeta, incompleteBeta, pdfSync, cdfSync ], quantileSync, [x, alpha, beta, lowerTail]); } exports.quantile = quantile; function randomSync(n, alpha, beta, seed, randoms) { return random_1.randSync(n, quantileSync, [alpha, beta], seed, randoms); } exports.randomSync = randomSync; function random(n, alpha, beta, seed) { return random_1.rand(n, quantileSync, [alpha, beta], seed, [ rf.newton, rf.bisection, rootFind, lnBeta, lnGamma, continuedFractionSolver, d, continuedFraction, lnIncompleteBeta, incompleteBeta, pdfSync, cdfSync ]); } exports.random = random; },{"./async":1,"./continuedFractionSolver":5,"./gamma":8,"./random":13,"./rootFind":14}],3:[function(require,module,exports){ "use strict"; const gamma = require("./gamma"); const beta = require("./beta"); const rf = require("./rootFind"); const cfs = require("./continuedFractionSolver"); const pf = require("./primeFactors"); const async_1 = require("./async"); const random_1 = require("./random"); // This import and then renaming of imports is necessary to allow the async module to // correctly generate web worker scripts. const lnGamma = gamma.lnGamma; const lnFactorial = gamma.lnFactorial; const incompleteBeta = beta.incompleteBeta; const discreteQuantileFind = rf.discreteQuantileFind; const continuedFractionSolver = cfs.continuedFractionSolver; const lnFactorialFractionEval = pf.lnFactorialFractionEval; function lnBinomialCoefficient(n, chooseK) { if (typeof n !== "number" || typeof chooseK !== "number") { throw new Error(`The binomial coefficient function is only defined for numeric${""} arguments n and k.`); } if (n < chooseK) { throw new Error(`The binomial coefficient function is only defined for n greater${""} than or equal to k.`); } if (!Number.isInteger(n) || !Number.isInteger(chooseK)) { throw new Error(`The binomial coefficient function is defined for integer${""} arguments n and k.`); } if (chooseK === 0 || chooseK === n) { return 0; } return lnFactorialFractionEval([n], [chooseK, n - chooseK]); } exports.lnBinomialCoefficient = lnBinomialCoefficient; function pmfSync(k, trials, probSuccess) { const p = probSuccess; if (!Number.isInteger(k) || k < 0 || k > trials) { return 0; } else { return Math.exp(lnBinomialCoefficient(trials, k) + (k * Math.log(p)) + ((trials - k) * Math.log(1 - p))); } } exports.pmfSync = pmfSync; function pmf(k, trials, probSuccess) { return async_1.asyncGen([ pf.primesLessThanOrEqualTo, pf._factorialPrimes, pf.factorialPrimes, lnFactorialFractionEval, lnBinomialCoefficient ], pmfSync, [k, trials, probSuccess]); } exports.pmf = pmf; function cdfSync(k, trials, probSuccess, lowerTail = true) { if (k < 0) { if (lowerTail) { return 0; } else { return 1; } } else if (k > trials) { if (lowerTail) { return 1; } else { return 0; } } else { k = Math.floor(k); if (lowerTail) { return incompleteBeta(1 - probSuccess, trials - k, k + 1); } else { return incompleteBeta(probSuccess, k + 1, trials - k); } } } exports.cdfSync = cdfSync; function cdf(k, trials, probSuccess, lowerTail = true) { return async_1.asyncGen([ beta.lnBeta, gamma.lnGamma, continuedFractionSolver, beta.d, beta.continuedFraction, beta.lnIncompleteBeta, beta.incompleteBeta ], cdfSync, [k, trials, probSuccess, lowerTail]); } exports.cdf = cdf; function quantileSync(p, trials, probSuccess, lowerTail = true) { function simplifiedCDF(val) { return cdfSync(val, trials, probSuccess, lowerTail); } if (p === 0) { if (lowerTail) { return 0; } else { return trials; } } else if (p === 1) { if (lowerTail) { return trials; } else { return 0; } } else { const mean = Math.floor(trials * p); return discreteQuantileFind(simplifiedCDF, p, trials, 0, mean, lowerTail); } } exports.quantileSync = quantileSync; function quantile(p, trials, probSuccess, lowerTail = true) { return async_1.asyncGen([ discreteQuantileFind, beta.lnBeta, gamma.lnGamma, continuedFractionSolver, beta.d, beta.continuedFraction, beta.lnIncompleteBeta, beta.incompleteBeta, cdfSync ], quantileSync, [p, trials, probSuccess, lowerTail]); } exports.quantile = quantile; function randomSync(n, trials, probSuccess, seed, randoms) { return random_1.randSync(n, quantileSync, [trials, probSuccess], seed, randoms); } exports.randomSync = randomSync; function random(n, trials, probSuccess, seed) { return random_1.rand(n, quantileSync, [trials, probSuccess], seed, [ discreteQuantileFind, beta.lnBeta, gamma.lnGamma, continuedFractionSolver, beta.d, beta.continuedFraction, beta.lnIncompleteBeta, beta.incompleteBeta, cdfSync ]); } exports.random = random; },{"./async":1,"./beta":2,"./continuedFractionSolver":5,"./gamma":8,"./primeFactors":12,"./random":13,"./rootFind":14}],4:[function(require,module,exports){ "use strict"; const continuedFractionSolver_1 = require("./continuedFractionSolver"); const gamma = require("./gamma"); const rf = require("./rootFind"); const async_1 = require("./async"); const random_1 = require("./random"); // This import and then renaming of imports is necessary to allow the async module to // correctly generate web worker scripts. const lowerIncompleteGamma = gamma.lowerIncompleteGamma; const upperIncompleteGamma = gamma.upperIncompleteGamma; const lnGamma = gamma.lnGamma; const rootFind = rf.rootFind; function pdfSync(x, degreesOfFreedom) { if (x <= 0) { return 0; } else { let k = degreesOfFreedom; let lnNumerator = ((k / 2) - 1) * Math.log(x) - (x / 2); let lnDenominator = ((k / 2) * Math.log(2)) + lnGamma(k / 2); return Math.exp(lnNumerator - lnDenominator); } } exports.pdfSync = pdfSync; function pdf(x, degreesOfFreedom) { return async_1.asyncGen([lnGamma, pdfSync], pdfSync, [x, degreesOfFreedom]); } exports.pdf = pdf; function cdfSync(x, degreesOfFreedom, lowerTail = true) { if (x <= 0) { if (lowerTail) { return 0; } else { return 1; } } else { if (lowerTail) { return lowerIncompleteGamma(x / 2, degreesOfFreedom / 2); } else { return upperIncompleteGamma(x / 2, degreesOfFreedom / 2); } } } exports.cdfSync = cdfSync; function cdf(x, degreesOfFreedom, lowerTail = true) { return async_1.asyncGen([ continuedFractionSolver_1.continuedFractionSolver, gamma.lnGamma, gamma.gammaContinuedFraction, gamma.lnLowerIncompleteGammaA, gamma.lnUpperIncompleteGammaB, gamma.lnLowerIncompleteGamma, gamma.lowerIncompleteGamma ], cdfSync, [x, degreesOfFreedom, lowerTail]); } exports.cdf = cdf; function quantileSync(p, degreesOfFreedom, lowerTail = true) { function f(val) { return cdfSync(val, degreesOfFreedom); } function fPrime(val) { return pdfSync(val, degreesOfFreedom); } if (p === 0) { if (lowerTail) { return 0; } else { return Number.POSITIVE_INFINITY; } } else if (p === 1) { if (lowerTail) { return Number.POSITIVE_INFINITY; } else { return 0; } } else { return rootFind(f, fPrime, p, 1, null, 0); } } exports.quantileSync = quantileSync; function quantile(p, degreesOfFreedom, lowerTail = true) { return async_1.asyncGen([ rf.newton, rf.bisection, rootFind, continuedFractionSolver_1.continuedFractionSolver, gamma.lnGamma, gamma.gammaContinuedFraction, gamma.lnLowerIncompleteGammaA, gamma.lnUpperIncompleteGammaB, gamma.lnLowerIncompleteGamma, gamma.lowerIncompleteGamma, pdfSync, cdfSync ], quantileSync, [p, degreesOfFreedom, lowerTail]); } exports.quantile = quantile; function randomSync(n, degreesOfFreedom, seed, randoms) { return random_1.randSync(n, quantileSync, [degreesOfFreedom], seed, randoms); } exports.randomSync = randomSync; function random(n, degreesOfFreedom, seed) { return random_1.rand(n, quantileSync, [degreesOfFreedom], seed, [ rf.newton, rf.bisection, rootFind, continuedFractionSolver_1.continuedFractionSolver, gamma.lnGamma, gamma.gammaContinuedFraction, gamma.lnLowerIncompleteGammaA, gamma.lnUpperIncompleteGammaB, gamma.lnLowerIncompleteGamma, gamma.lowerIncompleteGamma, pdfSync, cdfSync ]); } exports.random = random; },{"./async":1,"./continuedFractionSolver":5,"./gamma":8,"./random":13,"./rootFind":14}],5:[function(require,module,exports){ "use strict"; /** * This function uses the modified Lentz's method for solving continued fractions of the * form : * a1 a2 a3 a4 a5 * b0 + --- --- --- --- --- . . . * b1+ b2+ b3+ b4+ b5+ * * for a description of the algorithm, visit the web page: * http://www.aip.de/groups/soe/local/numres/bookcpdf/c5-2.pdf * * * @param a - a function that has one argument, j, that gives the a values in the * continued fraction representation above for j = 1, 2, 3, .... * @param b - a function that has one argument, j, that gives the b values in the * continued fraction representation above for j = 1, 2, 3, .... * @returns {*} - the estimated value of the continued fraction */ function continuedFractionSolver(a, b) { const EPS = 1e-15; const TINY = 1e-45; let fJ; let fJMinus1; let cJ; let cJMinus1; let dJ; let dJMinus1 = 0; let deltaJ; let j = 1; if (b(0) === 0) { fJMinus1 = TINY; } else { fJMinus1 = b(0); } cJMinus1 = fJMinus1; do { dJ = b(j) + (a(j) * dJMinus1); if (dJ === 0) { dJ = TINY; } cJ = b(j) + (a(j) / cJMinus1); if (cJ === 0) { cJ = TINY; } dJ = 1 / dJ; deltaJ = cJ * dJ; fJ = fJMinus1 * deltaJ; fJMinus1 = fJ; cJMinus1 = cJ; dJMinus1 = dJ; j++; } while (Math.abs(deltaJ - 1) >= EPS); return fJ; } exports.continuedFractionSolver = continuedFractionSolver; },{}],6:[function(require,module,exports){ "use strict"; const async_1 = require("./async"); const random_1 = require("./random"); const gamma = require("./gamma"); const cf = require("./continuedFractionSolver"); const rf = require("./rootFind"); const gammaCDF = gamma.gammaCDF; const rootFind = rf.rootFind; function pdfSync(x, lambda) { if (x < 0) { return 0; } else { return lambda * Math.exp((-lambda) * x); } } exports.pdfSync = pdfSync; function pdf(x, lambda) { return async_1.asyncGen([], pdfSync, [x, lambda]); } exports.pdf = pdf; function cdfSync(x, lambda, lowerTail = true) { if (x < 0) { if (lowerTail) { return 0; } else { return 1; } } else { if (lowerTail) { const possibleResult = 1 - Math.exp((-lambda) * x); if (possibleResult >= 0.1) { return possibleResult; } else { return gammaCDF(x, 1, 1 / lambda, true); } } else { return Math.exp((-lambda) * x); } } } exports.cdfSync = cdfSync; function cdf(x, lambda, lowerTail = true) { return async_1.asyncGen([ gammaCDF, gamma.lnGamma, gamma.gammaContinuedFraction, cf.continuedFractionSolver, gamma.lnLowerIncompleteGammaA, gamma.lnUpperIncompleteGammaB, gamma.lowerIncompleteGamma, gamma.upperIncompleteGamma ], cdfSync, [x, lambda, lowerTail]); } exports.cdf = cdf; function quantileSync(p, lambda, lowerTail = true) { function f(val) { return cdfSync(val, lambda, lowerTail); } function fPrime(val) { if (lowerTail) { return pdfSync(val, lambda); } else { return -pdfSync(val, lambda); } } const mean = 1 / lambda; if (p === 0) { if (lowerTail) { return 0; } else { return Number.POSITIVE_INFINITY; } } else if (p === 1) { if (lowerTail) { return Number.POSITIVE_INFINITY; } else { return 0; } } else { return rootFind(f, fPrime, p, mean, null, 0); } } exports.quantileSync = quantileSync; function quantile(p, lambda, lowerTail = true) { return async_1.asyncGen([ gammaCDF, gamma.lnGamma, gamma.gammaContinuedFraction, cf.continuedFractionSolver, gamma.lnLowerIncompleteGammaA, gamma.lnUpperIncompleteGammaB, gamma.lowerIncompleteGamma, gamma.upperIncompleteGamma, rootFind, rf.newton, rf.bisection, pdfSync, cdfSync ], quantileSync, [p, lambda, lowerTail]); } exports.quantile = quantile; function randomSync(n, lambda, seed, randoms) { return random_1.randSync(n, quantileSync, [lambda], seed, randoms); } exports.randomSync = randomSync; function random(n, lambda, seed) { return random_1.rand(n, quantileSync, [lambda], seed, [ gammaCDF, gamma.lnGamma, gamma.gammaContinuedFraction, cf.continuedFractionSolver, gamma.lnLowerIncompleteGammaA, gamma.lnUpperIncompleteGammaB, gamma.lowerIncompleteGamma, gamma.upperIncompleteGamma, rootFind, rf.newton, rf.bisection, pdfSync, cdfSync ]); } exports.random = random; },{"./async":1,"./continuedFractionSolver":5,"./gamma":8,"./random":13,"./rootFind":14}],7:[function(require,module,exports){ "use strict"; const gamma = require("./gamma"); const beta = require("./beta"); const rf = require("./rootFind"); const async_1 = require("./async"); const random_1 = require("./random"); const continuedFractionSolver_1 = require("./continuedFractionSolver"); // This import and then renaming of imports is necessary to allow the async module to // correctly generate web worker scripts. const lnGamma = gamma.lnGamma; const lnBeta = beta.lnBeta; const incompleteBeta = beta.incompleteBeta; const rootFind = rf.rootFind; function pdfSync(x, dof1, dof2) { if (x <= 0) { return 0; } else { const lnNumNum = (dof1 * Math.log(dof1 * x)) + (dof2 * Math.log(dof2)); const lnNumDenom = (dof1 + dof2) * Math.log((dof1 * x) + dof2); const lnNum = 0.5 * (lnNumNum - lnNumDenom); const lnDenom = Math.log(x) + lnBeta(dof1 / 2, dof2 / 2); return Math.exp(lnNum - lnDenom); } } exports.pdfSync = pdfSync; function pdf(x, dof1, dof2) { return async_1.asyncGen([beta.lnBeta, gamma.lnGamma,], pdfSync, [x, dof1, dof2]); } exports.pdf = pdf; function cdfSync(x, dof1, dof2, lowerTail = true) { if (x <= 0) { if (lowerTail) { return 0; } else { return 1; } } else { if (lowerTail) { return incompleteBeta((dof1 * x) / (dof2 + (dof1 * x)), dof1 / 2, dof2 / 2); } else { return incompleteBeta(dof2 / (dof2 + (dof1 * x)), dof2 / 2, dof1 / 2); } } } exports.cdfSync = cdfSync; function cdf(x, dof1, dof2, lowerTail = true) { return async_1.asyncGen([ beta.lnBeta, gamma.lnGamma, continuedFractionSolver_1.continuedFractionSolver, beta.d, beta.continuedFraction, beta.lnIncompleteBeta, beta.incompleteBeta ], cdfSync, [x, dof1, dof2, lowerTail]); } exports.cdf = cdf; function quantileSync(p, dof1, dof2, lowerTail = true) { function f(val) { return cdfSync(val, dof1, dof2); } function fPrime(val) { return pdfSync(val, dof1, dof2); } if (p === 0) { if (lowerTail) { return 0; } else { return Number.POSITIVE_INFINITY; } } else if (p === 1) { if (lowerTail) { return Number.POSITIVE_INFINITY; } else { return 0; } } else { return rootFind(f, fPrime, p, 1, null, 0); } } exports.quantileSync = quantileSync; function quantile(p, dof1, dof2, lowerTail = true) { return async_1.asyncGen([ rf.newton, rf.bisection, rootFind, beta.lnBeta, gamma.lnGamma, continuedFractionSolver_1.continuedFractionSolver, beta.d, beta.continuedFraction, beta.lnIncompleteBeta, beta.incompleteBeta, pdfSync, cdfSync ], quantileSync, [p, dof1, dof2, lowerTail]); } exports.quantile = quantile; function randomSync(n, dof1, dof2, seed, randoms) { return random_1.randSync(n, quantileSync, [dof1, dof2], seed, randoms); } exports.randomSync = randomSync; function random(n, dof1, dof2, seed) { return random_1.rand(n, quantileSync, [dof1, dof2], seed, [ rf.newton, rf.bisection, rootFind, beta.lnBeta, gamma.lnGamma, continuedFractionSolver_1.continuedFractionSolver, beta.d, beta.continuedFraction, beta.lnIncompleteBeta, beta.incompleteBeta, pdfSync, cdfSync ]); } exports.random = random; },{"./async":1,"./beta":2,"./continuedFractionSolver":5,"./gamma":8,"./random":13,"./rootFind":14}],8:[function(require,module,exports){ "use strict"; const async_1 = require("./async"); const random_1 = require("./random"); const cfs = require("./continuedFractionSolver"); const rf = require("./rootFind"); // This import and then renaming of imports is necessary to allow the async module to // correctly generate web worker scripts. const continuedFractionSolver = cfs.continuedFractionSolver; const rootFind = rf.rootFind; function lnGamma(val) { const EULER_MASCHERONI = 0.57721566490153286060651209008240243104215933593992; let result; var valFloor = Math.floor(val); var x = val - valFloor; if (x === 0) { result = 0; for (var i = 2; i < valFloor; i++) { result = result + Math.log(i); } } else { var sum = ((1 / 2) - x) * (EULER_MASCHERONI + Math.log(2)); sum = sum + ((1 - x) * Math.log(Math.PI)); sum = sum - ((1 / 2) * Math.log(Math.sin(Math.PI * x))); var infiniteSum = 0; for (var n = 1; n <= 100; n++) { var addition = (Math.sin(2 * Math.PI * n * x) * Math.log(n)) / n; infiniteSum = infiniteSum + addition; } sum = sum + ((1 / Math.PI) * infiniteSum); result = sum; for (var j = 0; j < valFloor; j++) { result = result + Math.log(x); x++; } } return result; } exports.lnGamma = lnGamma; /** * This function gives the log of the extended(on all non-negative n, possibly * non-integer n) factorial function. * @param n */ function lnFactorial(n) { if (typeof n !== "number") { throw new Error(`The log factorial function is only defined for numeric arguments.`); } if (n < 0) { throw new Error(`The log factorial of negative numbers in not defined.`); } if (n === 0) { return Number.NEGATIVE_INFINITY; } return lnGamma(n + 1); } exports.lnFactorial = lnFactorial; function gammaContinuedFraction(x, a) { function num(j) { if (j === 1) { return 1; } else if (j % 2 === 0) { return j / 2 - a; } else if (j % 2 === 1) { return Math.floor(j / 2); } else { throw new Error(`argument must be non-negative integer`); } } function denom(j) { if (j === 0) { return 0; } else if (j % 2 === 0) { return 1; } else if (j % 2 === 1) { return x; } else { throw new Error(`argument must be non-negative integer`); } } return continuedFractionSolver(num, denom); } exports.gammaContinuedFraction = gammaContinuedFraction; function lnLowerIncompleteGammaA(x, a) { const numerator = (a * Math.log(x)) - x; const denominator = lnGamma(a + 1); let summands = [1]; let infiniteSum = 0; let summandDenominator; let i = 1; do { summandDenominator = 0; for (var j = 1; j <= i; j++) { summandDenominator = summandDenominator + Math.log(a + j); } summands.push(Math.exp((i * Math.log(x)) - summandDenominator)); i++; } while (summands[i - 1] > 0); summands = summands.sort(); for (var k = 0; k < summands.length; k++) { infiniteSum += summands[k]; } return numerator - denominator + Math.log(infiniteSum); } exports.lnLowerIncompleteGammaA = lnLowerIncompleteGammaA; function lnUpperIncompleteGammaB(x, a) { const numerator = (a * Math.log(x)) - x; const denominator = lnGamma(a); const lnContinuedFraction = Math.log(gammaContinuedFraction(x, a)); return numerator - denominator + lnContinuedFraction; } exports.lnUpperIncompleteGammaB = lnUpperIncompleteGammaB; function lnLowerIncompleteGamma(x, a) { if (x <= a) { return lnLowerIncompleteGammaA(x, a); } else if (x > a && x <= a + 1) { const weight = x - a; const incompleteGammaA = lnLowerIncompleteGammaA(x, a); const incompleteGammaB = Math.log(1 - Math.exp(lnUpperIncompleteGammaB(x, a))); return ((1 - weight) * incompleteGammaA) + (weight * incompleteGammaB); } else { return Math.log(1 - Math.exp(lnUpperIncompleteGammaB(x, a))); } } exports.lnLowerIncompleteGamma = lnLowerIncompleteGamma; function lnUpperIncompleteGamma(x, a) { if (x <= a) { return Math.log(1 - Math.exp(lnLowerIncompleteGammaA(x, a))); } else if (x > a && x <= a + 1) { const weight = x - a; const incompleteGammaA = Math.log(1 - Math.exp(lnLowerIncompleteGammaA(x, a))); const incompleteGammaB = lnUpperIncompleteGammaB(x, a); return ((1 - weight) * incompleteGammaA) + (weight * incompleteGammaB); } else { return lnUpperIncompleteGammaB(x, a); } } exports.lnUpperIncompleteGamma = lnUpperIncompleteGamma; function lowerIncompleteGamma(x, a) { if (x <= a) { return Math.exp(lnLowerIncompleteGammaA(x, a)); } else if (x > a && x <= a + 1) { var weight = x - a; var incompleteGammaA = Math.exp(lnLowerIncompleteGammaA(x, a)); var incompleteGammaB = 1 - Math.exp(lnUpperIncompleteGammaB(x, a)); return (1 - weight) * incompleteGammaA + weight * incompleteGammaB; } else { return 1 - Math.exp(lnUpperIncompleteGammaB(x, a)); } } exports.lowerIncompleteGamma = lowerIncompleteGamma; function upperIncompleteGamma(x, a) { if (x <= a) { return 1 - Math.exp(lnLowerIncompleteGammaA(x, a)); } else if (x > a && x <= a + 1) { var weight = x - a; var incompleteGammaA = 1 - Math.exp(lnLowerIncompleteGammaA(x, a)); var incompleteGammaB = Math.exp(lnUpperIncompleteGammaB(x, a)); return (1 - weight) * incompleteGammaA + weight * incompleteGammaB; } else { return Math.exp(lnUpperIncompleteGammaB(x, a)); } } exports.upperIncompleteGamma = upperIncompleteGamma; function inverseLowerIncompleteGamma(p, a, initialEstimate) { if (!initialEstimate) { initialEstimate = a; } const lnLowIncompGamma = function (x) { return lnLowerIncompleteGamma(x, a); }; const derivativeLnLowIncompGammma = function (x) { return Math.exp(((a - 1) * Math.log(x)) - x - lnGamma(a) + lnLowerIncompleteGamma(x, a)); }; return rootFind(lnLowIncompGamma, derivativeLnLowIncompGammma, Math.log(p), initialEstimate, null, 0); } exports.inverseLowerIncompleteGamma = inverseLowerIncompleteGamma; function pdfSync(x, shape, scale) { if (x <= 0) { return 0; } else { const lnNum = ((shape - 1) * Math.log(x)) - (x / scale); const lnDenom = (lnGamma(shape) + (shape * Math.log(scale))); return Math.exp(lnNum - lnDenom); } } exports.pdfSync = pdfSync; function pdf(x, shape, scale) { return async_1.asyncGen([lnGamma], pdfSync, [x, shape, scale]); } exports.pdf = pdf; function cdfSync(x, shape, scale, lowerTail = true) { return gammaCDF(x, shape, scale, lowerTail); } exports.cdfSync = cdfSync; function gammaCDF(x, shape, scale, lowerTail = true) { if (x <= 0) { if (lowerTail) { return 0; } else { return 1; } } else { let a = x / scale; if (lowerTail) { return lowerIncompleteGamma(a, shape); } else { return upperIncompleteGamma(a, shape); } } } exports.gammaCDF = gammaCDF; function cdf(x, shape, scale, lowerTail = true) { return async_1.asyncGen([ lnGamma, gammaContinuedFraction, continuedFractionSolver, lnLowerIncompleteGammaA, lnUpperIncompleteGammaB, lowerIncompleteGamma, upperIncompleteGamma ], cdfSync, [x, shape, scale, lowerTail]); } exports.cdf = cdf; function quantileSync(p, shape, scale, lowerTail = true) { function f(val) { return cdfSync(val, shape, scale, lowerTail); } function fPrime(val) { if (lowerTail) { return pdfSync(val, shape, scale); } else { return -pdfSync(val, shape, scale); } } if (p === 0) { if (lowerTail) { return 0; } else { return Number.POSITIVE_INFINITY; } } else if (p === 1) { if (lowerTail) { return Number.POSITIVE_INFINITY; } else { return 0; } } else { const distMean = shape * scale; return rootFind(f, fPrime, p, distMean, null, 0); } } exports.quantileSync = quantileSync; function quantile(p, shape, scale, lowerTail = true) { return async_1.asyncGen([ lnGamma, gammaContinuedFraction, continuedFractionSolver, lnLowerIncompleteGammaA, lnUpperIncompleteGammaB, lowerIncompleteGamma, upperIncompleteGamma, rootFind, rf.newton, rf.bisection, pdfSync, gammaCDF, cdfSync ], quantileSync, [p, shape, scale, lowerTail]); } exports.quantile = quantile; function randomSync(n, shape, scale, seed, randoms) { return random_1.randSync(n, quantileSync, [shape, scale], seed, randoms); } exports.randomSync = randomSync; function random(n, shape, scale, seed) { return random_1.rand(n, quantileSync, [shape, scale], seed, [ lnGamma, gammaContinuedFraction, continuedFractionSolver, lnLowerIncompleteGammaA, lnUpperIncompleteGammaB, lowerIncompleteGamma, upperIncompleteGamma, rootFind, rf.newton, rf.bisection, pdfSync, gammaCDF, cdfSync ]); } exports.random = random; },{"./async":1,"./continuedFractionSolver":5,"./random":13,"./rootFind":14}],9:[function(require,module,exports){ "use strict"; const async_1 = require("./async"); const rf = require("./rootFind"); const pf = require("./primeFactors"); const random_1 = require("./random"); const discreteQuantileFind = rf.discreteQuantileFind; const lnFactorialFractionEval = pf.lnFactorialFractionEval; const primesLessThanOrEqualTo = pf.primesLessThanOrEqualTo; const _factorialPrimes = pf._factorialPrimes; const factorialPrimes = pf.factorialPrimes; function pmfSync(sampleSuccesses, draws, successPop, totalPop) { const k = sampleSuccesses; const n = draws; const K = successPop; const N = totalPop; if (N === 0 || K === 0 || n === 0) { if (k === 0) { return 1; } else { return 0; } } else if (N === K) { if (k === n) { return 1; } else { return 0; } } else if (N === n) { if (k === K) { return 1; } else { return 0; } } else if (k < 0 || k < (n + K - N) || k > K || k > n) { return 0; } else if (K === k) { if (n === k) { return Math.exp(lnFactorialFractionEval([N - K, n], [N])); } else { return Math.exp(lnFactorialFractionEval([N - K, n], [n - k, N])); } } else if (k === 0) { if (N - K - n === 0) { return Math.exp(lnFactorialFractionEval([N - K, N - n], [N])); } else { return Math.exp(lnFactorialFractionEval([N - K, N - n], [N - K - n, N])); } } else if ((N - K) === (n - k)) { return Math.exp(lnFactorialFractionEval([K, N - n, n], [K - k, k, N])); } else if (n === k) { return Math.exp(lnFactorialFractionEval([K, N - n], [K - n, N])); } else { return Math.exp(lnFactorialFractionEval([K, n, N - K, N - n], [N, k, K - k, n - k, N - K - n + k])); } } exports.pmfSync = pmfSync; function pmf(sampleSuccesses, draws, successPop, totalPop) { return async_1.asyncGen([ primesLessThanOrEqualTo, _factorialPrimes, factorialPrimes, lnFactorialFractionEval ], pmfSync, [sampleSuccesses, draws, successPop, totalPop]); } exports.pmf = pmf; function cdfSync(sampleSuccesses, draws, successPop, totalPop, lowerTail = true) { const k = sampleSuccesses; const n = draws; const K = successPop; const N = totalPop; let mean = n * (K / N); let easyCaseResult = _cdfSyncEasyCases(k, n, K, N, lowerTail); if (easyCaseResult !== null) { return easyCaseResult; } else { if (k <= mean) { const lnh0Eval = lnh0(n, K, N); return _cdfSyncHardCase(lnh0Eval, k, draws, successPop, totalPop, lowerTail); } else { const lnhMaxEval = lnhMax(n, K, N); return _cdfSyncHardCase(lnhMaxEval, k, draws, successPop, totalPop, lowerTail); } } } exports.cdfSync = cdfSync; function cdf(sampleSuccesses, draws, successPop, totalPop, lowerTail = true) { return async_1.asyncGen([ primesLessThanOrEqualTo, _factorialPrimes, factorialPrimes, lnFactorialFractionEval, _cdfSyncEasyCases, _cdfSyncHardCase, lnh0, lnhMax ], cdfSync, [sampleSuccesses, draws, successPop, totalPop, lowerTail]); } exports.cdf = cdf; function _cdfSyncEasyCases(k, n, K, N, lowerTail) { if (N === 0 || K === 0 || n === 0) { if (k >= 0) { if (lowerTail) { return 1; } else { return 0; } } else { if (lowerTail) { return 0; } else { return 1; } } } else if (N === K) { if (k >= n) { if (lowerTail) { return 1; } else { return 0; } } else { if (lowerTail) { return 0; } else { return 1; } } } else if (N === n) { if (k >= K) { if (lowerTail) { return 1; } else { return 0; } } else { if (lowerTail) { return 0; } else { return 1; } } } else if (k >= K || k >= n) { if (lowerTail) { return 1; } else { return 0; } } else if (k < 0 || k < (n + K - N)) { if (lowerTail) { return 0; } else { return 1; } } else { return null; } } function _cdfSyncHardCase(lnhEval, k, n, K, N, lowerTail) { let sum = 0; let current = lnhEval; let mean = n * (K / N); if (k <= mean) { for (let i = 0; i <= k; i++) { sum += Math.exp(current); current = Math.log(((K - i) * (n - i)) / ((i + 1) * (N - K - n + i + 1))) + current; } if (lowerTail) { return sum; } else { return 1 - sum; } } else { for (let i = Math.min(n, K); i > k; i--) { sum += Math.exp(current); current = Math.log((i * (N - K - n + i)) / ((K - i + 1) * (n - i + 1))) + current; } if (lowerTail) { return 1 - sum; } else { return sum; } } } function quantileSync(p, draws, successPop, totalPop, lowerTail = true, lnh0Eval, lnhMaxEval) { let h0log = lnh0Eval; let hMaxlog = lnhMaxEval; let mean = draws * (successPop / totalPop); function simplifiedCDF(val) { let easyCaseResult = _cdfSyncEasyCases(val, draws, successPop, totalPop, lowerTail); if (easyCaseResult !== null) { return easyCaseResult; } else { if (val <= mean) { h0log = !h0log ? lnh0(draws, successPop, totalPop) : h0log; return _cdfSyncHardCase(h0log, val, draws, successPop, totalPop, lowerTail); } else { hMaxlog = !hMaxlog ? lnhMax(draws, successPop, totalPop) : hMaxlog; return _cdfSyncHardCase(hMaxlog, val, draws, successPop, totalPop, lowerTail); } } } const max = Math.min(successPop, draws); const min = Math.max(0, draws + successPop - totalPop); if (p === 0) { if (lowerTail) { return min; } else { return max; } } else if (p === 1) { if (lowerTail) { return max; } else { return min; } } else { return discreteQuantileFind(simplifiedCDF, p, max, min, Math.floor(mean), lowerTail); } } exports.quantileSync = quantileSync; function quantile(p, draws, successPop, totalPop, lowerTail = true) { return async_1.asyncGen([ discreteQuantileFind, primesLessThanOrEqualTo, _factorialPrimes, factorialPrimes, lnFactorialFractionEval, _cdfSyncEasyCases, _cdfSyncHardCase, lnh0, lnhMax ], quantileSync, [p, draws, successPop, totalPop, lowerTail]); } exports.quantile = quantile; function lnh0(draws, successPop, totalPop) { const n = draws; const K = successPop; const N = totalPop; return lnFactorialFractionEval([N - K, N - n], [N, N - K - n]); } function lnhMax(draws, successPop, totalPop) { const n = draws; const K = successPop; const N = totalPop; const max = Math.min(n, K); return lnFactorialFractionEval([K, N - max], [N, K - max]); } function randomSync(n, draws, successPop, totalPop, seed, randoms) { // these two below are the heavy calculations for the distribution, so just do them once // here const lnh0Eval = lnh0(draws, successPop, totalPop); const lnhMaxEval = lnhMax(draws, successPop, totalPop); return random_1.randSync(n, quantileSync, [ draws, successPop, totalPop, true, lnh0Eval, lnhMaxEval ], seed, randoms); } exports.randomSync = randomSync; function random(n, draws, successPop, totalPop, seed) { return random_1.rand(n, quantileSync, [draws, successPop, totalPop], seed, [ discreteQuantileFind, primesLessThanOrEqualTo, _factorialPrimes, factorialPrimes, lnFactorialFractionEval, _cdfSyncEasyCases, _cdfSyncHardCase, lnh0, lnhMax ]); } exports.random = random; },{"./async":1,"./primeFactors":12,"./random":13,"./rootFind":14}],10:[function(require,module,exports){ "use strict"; const continuedFractionSolver_1 = require("./continuedFractionSolver"); const gamma = require("./gamma"); const rf = require("./rootFind"); const async_1 = require("./async"); const random_1 = require("./random"); // This import and then renaming of imports is necessary to allow the async module to // correctly generate web worker scripts. const lowerIncompleteGamma = gamma.lowerIncompleteGamma; const upperIncompleteGamma = gamma.upperIncompleteGamma; const rootFind = rf.rootFind; function pdfSync(x, mu, sigma) { if (typeof mu === "undefined" || mu === null) { mu = 0; } if (typeof sigma === "undefined" || sigma === null) { sigma = 1; } const coefficient = 1 / (sigma * Math.sqrt(2 * Math.PI)); const exponentNumerator = Math.pow((x - mu), 2); const exponentDenominator = 2 * Math.pow(sigma, 2); const exponent = -(exponentNumerator / exponentDenominator); return coefficient * Math.pow(Math.E, exponent); } exports.pdfSync = pdfSync; function pdf(x, mu, sigma) { function script(a, b, c) { return pdfSync(a, b, c); } return async_1.asyncGen([pdfSync], script, [x, mu, sigma]); } exports.pdf = pdf; function cdfSync(x, mu, sigma, lowerTail = true) { if (typeof mu === "undefined" || mu === null) { mu = 0; } if (typeof sigma === "undefined" || sigma === null) { sigma = 1; } const z = (x - mu) / sigma; function nonNegativeCase(val) { return (1 / 2) * (1 + lowerIncompleteGamma((val * val) / 2, 1 / 2)); } if ((z >= 0 && lowerTail) || (z < 0 && !lowerTail)) { return (1 / 2) + (lowerIncompleteGamma((x * x) / 2, 1 / 2) / 2); } else { return upperIncompleteGamma((x * x) / 2, 1 / 2) / 2; } } exports.cdfSync = cdfSync; function cdf(x, mu, sigma, lowerTail = true) { return async_1.asyncGen([ continuedFractionSolver_1.continuedFractionSolver, gamma.lnGamma, gamma.gammaContinuedFraction, gamma.lnLowerIncompleteGammaA, gamma.lnUpperIncompleteGammaB, gamma.lnLowerIncompleteGamma, gamma.lowerIncompleteGamma, gamma.upperIncompleteGamma ], cdfSync, [x, mu, sigma, lowerTail]); } exports.cdf = cdf; function quantileSync(p, mu, sigma, lowerTail = true) { if (typeof mu === "undefined" || mu === null) { mu = 0; } if (typeof sigma === "undefined" || sigma === null) { sigma = 1; } function f(val) { return cdfSync(val, 0, 1); } function fPrime(val) { if (lowerTail) { return pdfSync(val, 0, 1); } else { return -pdfSync(val, 0, 1); } } if (p === 0) { if (lowerTail) { return Number.NEGATIVE_INFINITY; } else { return Number.POSITIVE_INFINITY; } } else if (p === 1) { if (lowerTail) { return Number.POSITIVE_INFINITY; } else { return Number.NEGATIVE_INFINITY; } } else { let z = rootFind(f, fPrime, p, 0, null, null); return (z * sigma) + mu; } } exports.quantileSync = quantileSync; function quantile(p, mu, sigma, lowerTail = true) { return async_1.asyncGen([ rf.newton, rf.bisection, rootFind, continuedFractionSolver_1.continuedFractionSolver, gamma.lnGamma, gamma.gammaContinuedFraction, gamma.lnLowerIncompleteGammaA, gamma.lnUpperIncompleteGammaB, gamma.lnLowerIncompleteGamma, gamma.lowerIncompleteGamma, gamma.upperIncompleteGamma, pdfSync, cdfSync ], quantileSync, [p, mu, sigma, lowerTail]); } exports.quantile = quantile; function randomSync(n, mu, sigma, seed, randoms) { if (typeof mu === "undefined" || mu === null) { mu = 0; } if (typeof sigma === "undefined" || sigma === null) { sigma = 1; } return random_1.randSync(n, quantileSync, [mu, sigma, true], seed, randoms); } exports.randomSync = randomSync; function random(n, mu, sigma, seed) { return random_1.rand(n, quantileSync, [mu, sigma], seed, [ rf.newton, rf.bisection, rootFind, continuedFractionSolver_1.continuedFractionSolver, gamma.lnGamma, gamma.gammaContinuedFraction, gamma.lnLowerIncompleteGammaA, gamma.lnUpperIncompleteGammaB, gamma.lnLowerIncompleteGamma, gamma.lowerIncompleteGamma, gamma.upperIncompleteGamma, pdfSync, cdfSync ]); } exports.random = random; },{"./async":1,"./continuedFractionSolver":5,"./gamma":8,"./random":13,"./rootFind":14}],11:[function(require,module,expor