factory.js (2900B)
1 /** 2 * @license Apache-2.0 3 * 4 * Copyright (c) 2018 The Stdlib Authors. 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 'use strict'; 20 21 // MODULES // 22 23 var constantFunction = require( '@stdlib/utils/constant-function' ); 24 var cdf = require( './../../../../../base/dists/negative-binomial/cdf' ); 25 var erfcinv = require( '@stdlib/math/base/special/erfcinv' ); 26 var isnan = require( '@stdlib/math/base/assert/is-nan' ); 27 var round = require( '@stdlib/math/base/special/round' ); 28 var sqrt = require( '@stdlib/math/base/special/sqrt' ); 29 var SQRT2 = require( '@stdlib/constants/float64/sqrt-two' ); 30 var PINF = require( '@stdlib/constants/float64/pinf' ); 31 var search = require( './search.js' ); 32 33 34 // MAIN // 35 36 /** 37 * Returns a function for evaluating the quantile function for a negative binomial distribution with number of successes until experiment is stopped `r` and success probability `p`. 38 * 39 * @param {PositiveNumber} r - number of successes until experiment is stopped 40 * @param {Probability} p - success probability 41 * @returns {Function} quantile function 42 * 43 * @example 44 * var quantile = factory( 10.0, 0.5 ); 45 * var y = quantile( 0.1 ); 46 * // returns 5 47 * 48 * y = quantile( 0.9 ); 49 * // returns 16 50 */ 51 function factory( r, p ) { 52 var sigmaInv; 53 var sigma; 54 var mu; 55 var q; 56 if ( 57 isnan( r ) || 58 isnan( p ) || 59 r <= 0.0 || 60 p < 0.0 || 61 p > 1.0 62 ) { 63 return constantFunction( NaN ); 64 } 65 q = 1.0 - p; 66 mu = ( r * q ) / p; 67 sigma = sqrt( r * q ) / p; 68 sigmaInv = ( (2.0/p) - 1.0 ) / sigma; 69 return quantile; 70 71 /** 72 * Evaluates the quantile function for a negative binomial distribution. 73 * 74 * @private 75 * @param {Probability} k - input value 76 * @returns {NonNegativeInteger} evaluated quantile function 77 * 78 * @example 79 * var y = quantile( 0.3 ); 80 * // returns <number> 81 */ 82 function quantile( k ) { 83 var guess; 84 var corr; 85 var x2; 86 var x; 87 88 if ( isnan( k ) || k < 0.0 || k > 1.0 ) { 89 return NaN; 90 } 91 if ( k === 0.0 ) { 92 return 0.0; 93 } 94 if ( k === 1.0 ) { 95 return PINF; 96 } 97 98 // Cornish-Fisher expansion: 99 if ( k < 0.5 ) { 100 x = -erfcinv( 2.0 * k ) * SQRT2; 101 } else { 102 x = erfcinv( 2.0 * (1.0-k) ) * SQRT2; 103 } 104 x2 = x * x; 105 106 // Skewness correction: 107 corr = x + (sigmaInv * ( x2 - 1.0 ) / 6.0); 108 guess = round( mu + (sigma * corr) ); 109 return ( cdf( guess, r, p ) >= k ) ? 110 search.left( guess, k, r, p ) : 111 search.right( guess, k, r, p ); 112 } 113 } 114 115 116 // EXPORTS // 117 118 module.exports = factory;