time-to-botec

Benchmark sampling in different programming languages
Log | Files | Refs | README

assign.js (11641B)


      1 /* eslint-disable max-statements, max-lines */
      2 
      3 /**
      4 * @license Apache-2.0
      5 *
      6 * Copyright (c) 2018 The Stdlib Authors.
      7 *
      8 * Licensed under the Apache License, Version 2.0 (the "License");
      9 * you may not use this file except in compliance with the License.
     10 * You may obtain a copy of the License at
     11 *
     12 *    http://www.apache.org/licenses/LICENSE-2.0
     13 *
     14 * Unless required by applicable law or agreed to in writing, software
     15 * distributed under the License is distributed on an "AS IS" BASIS,
     16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     17 * See the License for the specific language governing permissions and
     18 * limitations under the License.
     19 *
     20 *
     21 * ## Notice
     22 *
     23 * The original C++ code and copyright notice are from the [Boost library]{@link http://www.boost.org/doc/libs/1_61_0/boost/math/special_functions/beta.hpp}. The implementation has been modified for JavaScript.
     24 *
     25 * ```text
     26 * (C) Copyright John Maddock 2006.
     27 * (C) Copyright Paul A. Bristow 2007.
     28 *
     29 * Use, modification and distribution are subject to the
     30 * Boost Software License, Version 1.0. (See accompanying file
     31 * LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
     32 * ```
     33 */
     34 
     35 'use strict';
     36 
     37 // MODULES //
     38 
     39 var isnan = require( './../../../../base/assert/is-nan' );
     40 var expm1 = require( './../../../../base/special/expm1' );
     41 var floor = require( './../../../../base/special/floor' );
     42 var log1p = require( './../../../../base/special/log1p' );
     43 var asin = require( './../../../../base/special/asin' );
     44 var beta = require( './../../../../base/special/beta' );
     45 var sqrt = require( './../../../../base/special/sqrt' );
     46 var exp = require( './../../../../base/special/exp' );
     47 var pow = require( './../../../../base/special/pow' );
     48 var max = require( './../../../../base/special/max' );
     49 var min = require( './../../../../base/special/min' );
     50 var MAX_FLOAT64 = require( '@stdlib/constants/float64/max' );
     51 var MIN_FLOAT64 = require( '@stdlib/constants/float64/smallest-normal' );
     52 var MAX_INT32 = require( '@stdlib/constants/int32/max' );
     53 var HALF_PI = require( '@stdlib/constants/float64/half-pi' );
     54 var PI = require( '@stdlib/constants/float64/pi' );
     55 var betaSmallBLargeASeries = require( './beta_small_b_large_a_series.js' );
     56 var risingFactorialRatio = require( './rising_factorial_ratio.js' );
     57 var ibetaPowerTerms = require( './ibeta_power_terms.js' );
     58 var ibetaFraction2 = require( './ibeta_fraction2.js');
     59 var binomialCCDF = require( './binomial_ccdf.js' );
     60 var ibetaAStep = require( './ibeta_a_step.js' );
     61 var ibetaSeries = require( './ibeta_series.js' );
     62 
     63 
     64 // VARIABLES //
     65 
     66 var ONE_OVER_PI = 1.0 / PI;
     67 
     68 
     69 // MAIN //
     70 
     71 /**
     72 * Evaluates the incomplete beta function and its first derivative and assigns results to a provided output array.
     73 *
     74 * ## Notes
     75 *
     76 * -   This function divides up the input range and selects the right implementation method for each domain.
     77 *
     78 * @param {Probability} x - function input
     79 * @param {NonNegativeNumber} a - function parameter
     80 * @param {NonNegativeNumber} b - function parameter
     81 * @param {boolean} regularized - boolean indicating if the function should evaluate the regularized boolean beta function
     82 * @param {boolean} upper - boolean indicating if the function should return the upper tail of the incomplete beta function instead
     83 * @param {(Array|TypedArray|Object)} out - output array
     84 * @param {integer} stride - output array stride
     85 * @param {NonNegativeInteger} offset - output array index offset
     86 * @returns {(Array|TypedArray|Object)} function value and first derivative
     87 *
     88 * @example
     89 * var out = ibetaImp( 0.5, 2.0, 2.0, false, false, [ 0.0, 0.0 ], 1, 0 );
     90 * // returns [ ~0.083, ~1.5 ]
     91 *
     92 * @example
     93 * var out = ibetaImp( 0.2, 1.0, 2.0, false, true, [ 0.0, 0.0 ], 1, 0 );
     94 * // returns [ 0.32, 1.6 ]
     95 *
     96 * @example
     97 * var out = ibetaImp( 0.2, 1.0, 2.0, true, true, [ 0.0, 0.0 ], 1, 0 );
     98 * // returns [ 0.64, 1.6 ]
     99 */
    100 function ibetaImp( x, a, b, regularized, upper, out, stride, offset ) {
    101 	var lambda;
    102 	var prefix;
    103 	var fract;
    104 	var bbar;
    105 	var div;
    106 	var tmp;
    107 	var i0;
    108 	var i1;
    109 	var k;
    110 	var n;
    111 	var p;
    112 	var y;
    113 
    114 	y = 1.0 - x;
    115 	i0 = offset;
    116 	i1 = offset + stride;
    117 
    118 	// Derivative not set...
    119 	out[ i1 ] = -1;
    120 	if ( isnan( x ) || x < 0.0 || x > 1.0 ) {
    121 		out[ i0 ] = NaN;
    122 		out[ i1 ] = NaN;
    123 		return out;
    124 	}
    125 	if ( regularized ) {
    126 		if ( a < 0.0 || b < 0.0 ) {
    127 			out[ i0 ] = NaN;
    128 			out[ i1 ] = NaN;
    129 			return out;
    130 		}
    131 		// Extend to a few very special cases...
    132 		if ( a === 0.0 ) {
    133 			if ( b === 0.0 ) {
    134 				out[ i0 ] = NaN;
    135 				out[ i1 ] = NaN;
    136 				return out;
    137 			}
    138 			if ( b > 0.0 ) {
    139 				out[ i0 ] = ( upper ) ? 0.0 : 1.0;
    140 				return out;
    141 			}
    142 		} else if ( b === 0.0 ) {
    143 			if ( a > 0.0 ) {
    144 				out[ i0 ] = ( upper ) ? 1.0 : 0.0;
    145 				return out;
    146 			}
    147 		}
    148 	} else if ( a <= 0.0 || b <= 0.0 ) {
    149 		out[ i0 ] = NaN;
    150 		out[ i1 ] = NaN;
    151 		return out;
    152 	}
    153 	if ( x === 0.0 ) {
    154 		if ( a === 1.0 ) {
    155 			out[ i1 ] = 1.0;
    156 		} else {
    157 			out[ i1 ] = ( a < 1.0 ) ? MAX_FLOAT64 / 2.0 : MIN_FLOAT64 * 2.0;
    158 		}
    159 		if ( upper ) {
    160 			out[ i0 ] = ( regularized ) ? 1.0 : beta( a, b );
    161 			return out;
    162 		}
    163 		out[ i0 ] = 0.0;
    164 		return out;
    165 	}
    166 	if ( x === 1.0 ) {
    167 		if ( b === 1.0 ) {
    168 			out[ i1 ] = 1.0;
    169 		} else {
    170 			out[ i1 ] = ( b < 1.0 ) ? MAX_FLOAT64 / 2.0 : MIN_FLOAT64 * 2.0;
    171 		}
    172 		if ( upper ) {
    173 			out[ i0 ] = 0.0;
    174 		} else {
    175 			out[ i0 ] = ( regularized ) ? 1.0 : beta( a, b );
    176 		}
    177 		return out;
    178 	}
    179 	if ( a === 0.5 && b === 0.5 ) {
    180 		out[ i1 ] = ONE_OVER_PI * sqrt( y * x );
    181 
    182 		// We have an arcsine distribution:
    183 		p = ( upper ) ? asin( sqrt(y) ) : asin( sqrt(x) );
    184 		p /= HALF_PI;
    185 		if ( !regularized ) {
    186 			p *= PI;
    187 		}
    188 		out[ i0 ] = p;
    189 		return out;
    190 	}
    191 	if ( a === 1.0 ) {
    192 		tmp = b;
    193 		b = a;
    194 		a = tmp;
    195 
    196 		tmp = y;
    197 		y = x;
    198 		x = tmp;
    199 
    200 		upper = !upper;
    201 	}
    202 	if ( b === 1.0 ) {
    203 		// Special case see: http://functions.wolfram.com/GammaBetaErf/BetaRegularized/03/01/01/
    204 		if ( a === 1.0 ) {
    205 			out[ i0 ] = ( upper ) ? y : x;
    206 			out[ i1 ] = 1.0;
    207 			return out;
    208 		}
    209 		out[ i1 ] = a * pow( x, a - 1.0 );
    210 		if ( y < 0.5 ) {
    211 			p = ( upper ) ? -expm1( a * log1p(-y) ) : exp( a * log1p(-y) );
    212 		} else {
    213 			p = ( upper ) ? -( pow( x, a ) - 1.0 ) : pow( x, a );
    214 		}
    215 		if ( !regularized ) {
    216 			p /= a;
    217 		}
    218 		out[ i0 ] = p;
    219 		return out;
    220 	}
    221 	if ( min( a, b ) <= 1.0 ) {
    222 		if ( x > 0.5 ) {
    223 			tmp = b;
    224 			b = a;
    225 			a = tmp;
    226 
    227 			tmp = y;
    228 			y = x;
    229 			x = tmp;
    230 
    231 			upper = !upper;
    232 		}
    233 		if ( max( a, b ) <= 1.0 ) {
    234 			// Both a,b < 1:
    235 			if ( (a >= min( 0.2, b ) ) || ( pow(x, a) <= 0.9 ) ) {
    236 				if ( upper ) {
    237 					fract = -( ( regularized ) ? 1.0 : beta( a, b ) );
    238 					upper = false;
    239 					fract = -ibetaSeries( a, b, x, fract, regularized, out, y );
    240 				} else {
    241 					fract = ibetaSeries( a, b, x, 0, regularized, out, y );
    242 				}
    243 			} else {
    244 				tmp = b;
    245 				b = a;
    246 				a = tmp;
    247 
    248 				tmp = y;
    249 				y = x;
    250 				x = tmp;
    251 
    252 				upper = !upper;
    253 				if ( y >= 0.3 ) {
    254 					if ( upper ) {
    255 						fract = -( ( regularized ) ? 1.0 : beta( a, b ) );
    256 						upper = false;
    257 						fract = -ibetaSeries( a, b, x, fract, regularized, out, y ); // eslint-disable-line max-len
    258 					} else {
    259 						fract = ibetaSeries( a, b, x, 0, regularized, out, y );
    260 					}
    261 				} else {
    262 					// Sidestep on a, and then use the series representation:
    263 					if ( regularized ) {
    264 						prefix = 1;
    265 					} else {
    266 						prefix = risingFactorialRatio( a + b, a, 20 );
    267 					}
    268 					fract = ibetaAStep( a, b, x, y, 20, regularized, out );
    269 					if ( upper ) {
    270 						fract -= ( ( regularized ) ? 1 : beta( a, b ) );
    271 						upper = false;
    272 						fract = -betaSmallBLargeASeries( a + 20.0, b, x, y, fract, prefix, regularized ); // eslint-disable-line max-len
    273 					} else {
    274 						fract = betaSmallBLargeASeries( a + 20.0, b, x, y, fract, prefix, regularized ); // eslint-disable-line max-len
    275 					}
    276 				}
    277 			}
    278 		} else if ( b <= 1.0 || ( x < 0.1 && ( pow( b * x, a ) <= 0.7 ) ) ) {
    279 			if ( upper ) {
    280 				fract = -( ( regularized ) ? 1 : beta( a, b ) );
    281 				upper = false;
    282 				fract = -ibetaSeries( a, b, x, fract, regularized, out, y );
    283 			} else {
    284 				fract = ibetaSeries( a, b, x, 0.0, regularized, out, y );
    285 			}
    286 		} else {
    287 			tmp = b;
    288 			b = a;
    289 			a = tmp;
    290 
    291 			tmp = y;
    292 			y = x;
    293 			x = tmp;
    294 			upper = !upper;
    295 
    296 			if ( y >= 0.3 ) {
    297 				if (upper) {
    298 					fract = -(( regularized ) ? 1.0 : beta( a, b ));
    299 					upper = false;
    300 					fract = -ibetaSeries( a, b, x, fract, regularized, out, y );
    301 				} else {
    302 					fract = ibetaSeries( a, b, x, 0.0, regularized, out, y );
    303 				}
    304 			}
    305 			else if ( a >= 15.0 ) {
    306 				if ( upper ) {
    307 					fract = -(( regularized ) ? 1.0 : beta( a, b ));
    308 					upper = false;
    309 					fract = -betaSmallBLargeASeries( a, b, x, y, fract, 1.0, regularized ); // eslint-disable-line max-len
    310 				} else {
    311 					fract = betaSmallBLargeASeries( a, b, x, y, 0.0, 1.0, regularized ); // eslint-disable-line max-len
    312 				}
    313 			}
    314 			else {
    315 				if ( regularized ) {
    316 					prefix = 1;
    317 				} else {
    318 					// Sidestep to improve errors:
    319 					prefix = risingFactorialRatio( a + b, a, 20.0 );
    320 				}
    321 				fract = ibetaAStep( a, b, x, y, 20.0, regularized, out );
    322 				if ( upper ) {
    323 					fract -= ( ( regularized ) ? 1.0 : beta( a, b ) );
    324 					upper = false;
    325 					fract = -betaSmallBLargeASeries( a + 20.0, b, x, y, fract, prefix, regularized ); // eslint-disable-line max-len
    326 				} else {
    327 					fract = betaSmallBLargeASeries( a + 20.0, b, x, y, fract, prefix, regularized ); // eslint-disable-line max-len
    328 				}
    329 			}
    330 		}
    331 	} else {
    332 		// Both a,b >= 1:
    333 		if ( a < b ) {
    334 			lambda = a - ( (a + b) * x );
    335 		} else {
    336 			lambda = ( (a + b) * y ) - b;
    337 		}
    338 		if ( lambda < 0.0 ) {
    339 			tmp = b;
    340 			b = a;
    341 			a = tmp;
    342 
    343 			tmp = y;
    344 			y = x;
    345 			x = tmp;
    346 			upper = !upper;
    347 		}
    348 		if ( b < 40.0 ) {
    349 			if (
    350 				floor(a) === a &&
    351 				floor(b) === b &&
    352 				a < MAX_INT32 - 100
    353 			) {
    354 				// Relate to the binomial distribution and use a finite sum:
    355 				k = a - 1.0;
    356 				n = b + k;
    357 				fract = binomialCCDF( n, k, x, y );
    358 				if ( !regularized ) {
    359 					fract *= beta( a, b );
    360 				}
    361 			}
    362 			else if ( b * x <= 0.7 ) {
    363 				if ( upper ) {
    364 					fract = -( ( regularized ) ? 1.0 : beta( a, b ) );
    365 					upper = false;
    366 					fract = -ibetaSeries( a, b, x, fract, regularized, out, y );
    367 				} else {
    368 					fract = ibetaSeries( a, b, x, 0.0, regularized, out, y );
    369 				}
    370 			}
    371 			else if ( a > 15.0 ) {
    372 				// Sidestep so we can use the series representation:
    373 				n = floor( b );
    374 				if ( n === b ) {
    375 					n -= 1;
    376 				}
    377 				bbar = b - n;
    378 				if ( regularized ) {
    379 					prefix = 1;
    380 				} else {
    381 					prefix = risingFactorialRatio( a + bbar, bbar, n );
    382 				}
    383 				fract = ibetaAStep( bbar, a, y, x, n, regularized );
    384 				fract = betaSmallBLargeASeries( a, bbar, x, y, fract, 1.0, regularized ); // eslint-disable-line max-len
    385 				fract /= prefix;
    386 			}
    387 			else if ( regularized ) {
    388 				n = floor( b );
    389 				bbar = b - n;
    390 				if ( bbar <= 0 ) {
    391 					n -= 1;
    392 					bbar += 1;
    393 				}
    394 				fract = ibetaAStep( bbar, a, y, x, n, regularized );
    395 				fract += ibetaAStep( a, bbar, x, y, 20.0, regularized );
    396 				if ( upper ) {
    397 					fract -= 1;
    398 				}
    399 				fract = betaSmallBLargeASeries( a + 20.0, bbar, x, y, fract, 1, regularized ); // eslint-disable-line max-len
    400 				if ( upper ) {
    401 					fract = -fract;
    402 					upper = false;
    403 				}
    404 			}
    405 			else {
    406 				fract = ibetaFraction2( a, b, x, y, regularized, out );
    407 			}
    408 		} else {
    409 			fract = ibetaFraction2( a, b, x, y, regularized, out );
    410 		}
    411 	}
    412 	if ( out[ i1 ] < 0.0 ) {
    413 		out[ i1 ] = ibetaPowerTerms( a, b, x, y, true );
    414 	}
    415 	div = y * x;
    416 	if ( out[ i1 ] !== 0.0 ) {
    417 		if ( ( MAX_FLOAT64 * div < out[ i1 ] ) ) {
    418 			// Overflow, return an arbitrarily large value:
    419 			out[ i1 ] = MAX_FLOAT64 / 2.0;
    420 		} else {
    421 			out[ i1 ] /= div;
    422 		}
    423 	}
    424 	out[ i0 ] = ( upper ) ? ( ( regularized ) ? 1.0 : beta( a, b ) ) - fract : fract; // eslint-disable-line max-len
    425 	return out;
    426 }
    427 
    428 
    429 // EXPORTS //
    430 
    431 module.exports = ibetaImp;