time-to-botec

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

jstat.js (129959B)


      1 (function (window, factory) {
      2     if (typeof exports === 'object') {
      3         module.exports = factory();
      4     } else if (typeof define === 'function' && define.amd) {
      5         define(factory);
      6     } else {
      7         window.jStat = factory();
      8     }
      9 })(this, function () {
     10 var jStat = (function(Math, undefined) {
     11 
     12 // For quick reference.
     13 var concat = Array.prototype.concat;
     14 var slice = Array.prototype.slice;
     15 var toString = Object.prototype.toString;
     16 
     17 // Calculate correction for IEEE error
     18 // TODO: This calculation can be improved.
     19 function calcRdx(n, m) {
     20   var val = n > m ? n : m;
     21   return Math.pow(10,
     22                   17 - ~~(Math.log(((val > 0) ? val : -val)) * Math.LOG10E));
     23 }
     24 
     25 
     26 var isArray = Array.isArray || function isArray(arg) {
     27   return toString.call(arg) === '[object Array]';
     28 };
     29 
     30 
     31 function isFunction(arg) {
     32   return toString.call(arg) === '[object Function]';
     33 }
     34 
     35 
     36 function isNumber(num) {
     37   return (typeof num === 'number') ? num - num === 0 : false;
     38 }
     39 
     40 
     41 // Converts the jStat matrix to vector.
     42 function toVector(arr) {
     43   return concat.apply([], arr);
     44 }
     45 
     46 
     47 // The one and only jStat constructor.
     48 function jStat() {
     49   return new jStat._init(arguments);
     50 }
     51 
     52 
     53 // TODO: Remove after all references in src files have been removed.
     54 jStat.fn = jStat.prototype;
     55 
     56 
     57 // By separating the initializer from the constructor it's easier to handle
     58 // always returning a new instance whether "new" was used or not.
     59 jStat._init = function _init(args) {
     60   // If first argument is an array, must be vector or matrix.
     61   if (isArray(args[0])) {
     62     // Check if matrix.
     63     if (isArray(args[0][0])) {
     64       // See if a mapping function was also passed.
     65       if (isFunction(args[1]))
     66         args[0] = jStat.map(args[0], args[1]);
     67       // Iterate over each is faster than this.push.apply(this, args[0].
     68       for (var i = 0; i < args[0].length; i++)
     69         this[i] = args[0][i];
     70       this.length = args[0].length;
     71 
     72     // Otherwise must be a vector.
     73     } else {
     74       this[0] = isFunction(args[1]) ? jStat.map(args[0], args[1]) : args[0];
     75       this.length = 1;
     76     }
     77 
     78   // If first argument is number, assume creation of sequence.
     79   } else if (isNumber(args[0])) {
     80     this[0] = jStat.seq.apply(null, args);
     81     this.length = 1;
     82 
     83   // Handle case when jStat object is passed to jStat.
     84   } else if (args[0] instanceof jStat) {
     85     // Duplicate the object and pass it back.
     86     return jStat(args[0].toArray());
     87 
     88   // Unexpected argument value, return empty jStat object.
     89   // TODO: This is strange behavior. Shouldn't this throw or some such to let
     90   // the user know they had bad arguments?
     91   } else {
     92     this[0] = [];
     93     this.length = 1;
     94   }
     95 
     96   return this;
     97 };
     98 jStat._init.prototype = jStat.prototype;
     99 jStat._init.constructor = jStat;
    100 
    101 
    102 // Utility functions.
    103 // TODO: for internal use only?
    104 jStat.utils = {
    105   calcRdx: calcRdx,
    106   isArray: isArray,
    107   isFunction: isFunction,
    108   isNumber: isNumber,
    109   toVector: toVector
    110 };
    111 
    112 
    113 jStat._random_fn = Math.random;
    114 jStat.setRandom = function setRandom(fn) {
    115   if (typeof fn !== 'function')
    116     throw new TypeError('fn is not a function');
    117   jStat._random_fn = fn;
    118 };
    119 
    120 
    121 // Easily extend the jStat object.
    122 // TODO: is this seriously necessary?
    123 jStat.extend = function extend(obj) {
    124   var i, j;
    125 
    126   if (arguments.length === 1) {
    127     for (j in obj)
    128       jStat[j] = obj[j];
    129     return this;
    130   }
    131 
    132   for (i = 1; i < arguments.length; i++) {
    133     for (j in arguments[i])
    134       obj[j] = arguments[i][j];
    135   }
    136 
    137   return obj;
    138 };
    139 
    140 
    141 // Returns the number of rows in the matrix.
    142 jStat.rows = function rows(arr) {
    143   return arr.length || 1;
    144 };
    145 
    146 
    147 // Returns the number of columns in the matrix.
    148 jStat.cols = function cols(arr) {
    149   return arr[0].length || 1;
    150 };
    151 
    152 
    153 // Returns the dimensions of the object { rows: i, cols: j }
    154 jStat.dimensions = function dimensions(arr) {
    155   return {
    156     rows: jStat.rows(arr),
    157     cols: jStat.cols(arr)
    158   };
    159 };
    160 
    161 
    162 // Returns a specified row as a vector or return a sub matrix by pick some rows
    163 jStat.row = function row(arr, index) {
    164   if (isArray(index)) {
    165     return index.map(function(i) {
    166       return jStat.row(arr, i);
    167     })
    168   }
    169   return arr[index];
    170 };
    171 
    172 
    173 // return row as array
    174 // rowa([[1,2],[3,4]],0) -> [1,2]
    175 jStat.rowa = function rowa(arr, i) {
    176   return jStat.row(arr, i);
    177 };
    178 
    179 
    180 // Returns the specified column as a vector or return a sub matrix by pick some
    181 // columns
    182 jStat.col = function col(arr, index) {
    183   if (isArray(index)) {
    184     var submat = jStat.arange(arr.length).map(function() {
    185       return new Array(index.length);
    186     });
    187     index.forEach(function(ind, i){
    188       jStat.arange(arr.length).forEach(function(j) {
    189         submat[j][i] = arr[j][ind];
    190       });
    191     });
    192     return submat;
    193   }
    194   var column = new Array(arr.length);
    195   for (var i = 0; i < arr.length; i++)
    196     column[i] = [arr[i][index]];
    197   return column;
    198 };
    199 
    200 
    201 // return column as array
    202 // cola([[1,2],[3,4]],0) -> [1,3]
    203 jStat.cola = function cola(arr, i) {
    204   return jStat.col(arr, i).map(function(a){ return a[0] });
    205 };
    206 
    207 
    208 // Returns the diagonal of the matrix
    209 jStat.diag = function diag(arr) {
    210   var nrow = jStat.rows(arr);
    211   var res = new Array(nrow);
    212   for (var row = 0; row < nrow; row++)
    213     res[row] = [arr[row][row]];
    214   return res;
    215 };
    216 
    217 
    218 // Returns the anti-diagonal of the matrix
    219 jStat.antidiag = function antidiag(arr) {
    220   var nrow = jStat.rows(arr) - 1;
    221   var res = new Array(nrow);
    222   for (var i = 0; nrow >= 0; nrow--, i++)
    223     res[i] = [arr[i][nrow]];
    224   return res;
    225 };
    226 
    227 // Transpose a matrix or array.
    228 jStat.transpose = function transpose(arr) {
    229   var obj = [];
    230   var objArr, rows, cols, j, i;
    231 
    232   // Make sure arr is in matrix format.
    233   if (!isArray(arr[0]))
    234     arr = [arr];
    235 
    236   rows = arr.length;
    237   cols = arr[0].length;
    238 
    239   for (i = 0; i < cols; i++) {
    240     objArr = new Array(rows);
    241     for (j = 0; j < rows; j++)
    242       objArr[j] = arr[j][i];
    243     obj.push(objArr);
    244   }
    245 
    246   // If obj is vector, return only single array.
    247   return obj.length === 1 ? obj[0] : obj;
    248 };
    249 
    250 
    251 // Map a function to an array or array of arrays.
    252 // "toAlter" is an internal variable.
    253 jStat.map = function map(arr, func, toAlter) {
    254   var row, nrow, ncol, res, col;
    255 
    256   if (!isArray(arr[0]))
    257     arr = [arr];
    258 
    259   nrow = arr.length;
    260   ncol = arr[0].length;
    261   res = toAlter ? arr : new Array(nrow);
    262 
    263   for (row = 0; row < nrow; row++) {
    264     // if the row doesn't exist, create it
    265     if (!res[row])
    266       res[row] = new Array(ncol);
    267     for (col = 0; col < ncol; col++)
    268       res[row][col] = func(arr[row][col], row, col);
    269   }
    270 
    271   return res.length === 1 ? res[0] : res;
    272 };
    273 
    274 
    275 // Cumulatively combine the elements of an array or array of arrays using a function.
    276 jStat.cumreduce = function cumreduce(arr, func, toAlter) {
    277   var row, nrow, ncol, res, col;
    278 
    279   if (!isArray(arr[0]))
    280     arr = [arr];
    281 
    282   nrow = arr.length;
    283   ncol = arr[0].length;
    284   res = toAlter ? arr : new Array(nrow);
    285 
    286   for (row = 0; row < nrow; row++) {
    287     // if the row doesn't exist, create it
    288     if (!res[row])
    289       res[row] = new Array(ncol);
    290     if (ncol > 0)
    291       res[row][0] = arr[row][0];
    292     for (col = 1; col < ncol; col++)
    293       res[row][col] = func(res[row][col-1], arr[row][col]);
    294   }
    295   return res.length === 1 ? res[0] : res;
    296 };
    297 
    298 
    299 // Destructively alter an array.
    300 jStat.alter = function alter(arr, func) {
    301   return jStat.map(arr, func, true);
    302 };
    303 
    304 
    305 // Generate a rows x cols matrix according to the supplied function.
    306 jStat.create = function  create(rows, cols, func) {
    307   var res = new Array(rows);
    308   var i, j;
    309 
    310   if (isFunction(cols)) {
    311     func = cols;
    312     cols = rows;
    313   }
    314 
    315   for (i = 0; i < rows; i++) {
    316     res[i] = new Array(cols);
    317     for (j = 0; j < cols; j++)
    318       res[i][j] = func(i, j);
    319   }
    320 
    321   return res;
    322 };
    323 
    324 
    325 function retZero() { return 0; }
    326 
    327 
    328 // Generate a rows x cols matrix of zeros.
    329 jStat.zeros = function zeros(rows, cols) {
    330   if (!isNumber(cols))
    331     cols = rows;
    332   return jStat.create(rows, cols, retZero);
    333 };
    334 
    335 
    336 function retOne() { return 1; }
    337 
    338 
    339 // Generate a rows x cols matrix of ones.
    340 jStat.ones = function ones(rows, cols) {
    341   if (!isNumber(cols))
    342     cols = rows;
    343   return jStat.create(rows, cols, retOne);
    344 };
    345 
    346 
    347 // Generate a rows x cols matrix of uniformly random numbers.
    348 jStat.rand = function rand(rows, cols) {
    349   if (!isNumber(cols))
    350     cols = rows;
    351   return jStat.create(rows, cols, jStat._random_fn);
    352 };
    353 
    354 
    355 function retIdent(i, j) { return i === j ? 1 : 0; }
    356 
    357 
    358 // Generate an identity matrix of size row x cols.
    359 jStat.identity = function identity(rows, cols) {
    360   if (!isNumber(cols))
    361     cols = rows;
    362   return jStat.create(rows, cols, retIdent);
    363 };
    364 
    365 
    366 // Tests whether a matrix is symmetric
    367 jStat.symmetric = function symmetric(arr) {
    368   var size = arr.length;
    369   var row, col;
    370 
    371   if (arr.length !== arr[0].length)
    372     return false;
    373 
    374   for (row = 0; row < size; row++) {
    375     for (col = 0; col < size; col++)
    376       if (arr[col][row] !== arr[row][col])
    377         return false;
    378   }
    379 
    380   return true;
    381 };
    382 
    383 
    384 // Set all values to zero.
    385 jStat.clear = function clear(arr) {
    386   return jStat.alter(arr, retZero);
    387 };
    388 
    389 
    390 // Generate sequence.
    391 jStat.seq = function seq(min, max, length, func) {
    392   if (!isFunction(func))
    393     func = false;
    394 
    395   var arr = [];
    396   var hival = calcRdx(min, max);
    397   var step = (max * hival - min * hival) / ((length - 1) * hival);
    398   var current = min;
    399   var cnt;
    400 
    401   // Current is assigned using a technique to compensate for IEEE error.
    402   // TODO: Needs better implementation.
    403   for (cnt = 0;
    404        current <= max && cnt < length;
    405        cnt++, current = (min * hival + step * hival * cnt) / hival) {
    406     arr.push((func ? func(current, cnt) : current));
    407   }
    408 
    409   return arr;
    410 };
    411 
    412 
    413 // arange(5) -> [0,1,2,3,4]
    414 // arange(1,5) -> [1,2,3,4]
    415 // arange(5,1,-1) -> [5,4,3,2]
    416 jStat.arange = function arange(start, end, step) {
    417   var rl = [];
    418   var i;
    419   step = step || 1;
    420   if (end === undefined) {
    421     end = start;
    422     start = 0;
    423   }
    424   if (start === end || step === 0) {
    425     return [];
    426   }
    427   if (start < end && step < 0) {
    428     return [];
    429   }
    430   if (start > end && step > 0) {
    431     return [];
    432   }
    433   if (step > 0) {
    434     for (i = start; i < end; i += step) {
    435       rl.push(i);
    436     }
    437   } else {
    438     for (i = start; i > end; i += step) {
    439       rl.push(i);
    440     }
    441   }
    442   return rl;
    443 };
    444 
    445 
    446 // A=[[1,2,3],[4,5,6],[7,8,9]]
    447 // slice(A,{row:{end:2},col:{start:1}}) -> [[2,3],[5,6]]
    448 // slice(A,1,{start:1}) -> [5,6]
    449 // as numpy code A[:2,1:]
    450 jStat.slice = (function(){
    451   function _slice(list, start, end, step) {
    452     // note it's not equal to range.map mode it's a bug
    453     var i;
    454     var rl = [];
    455     var length = list.length;
    456     if (start === undefined && end === undefined && step === undefined) {
    457       return jStat.copy(list);
    458     }
    459 
    460     start = start || 0;
    461     end = end || list.length;
    462     start = start >= 0 ? start : length + start;
    463     end = end >= 0 ? end : length + end;
    464     step = step || 1;
    465     if (start === end || step === 0) {
    466       return [];
    467     }
    468     if (start < end && step < 0) {
    469       return [];
    470     }
    471     if (start > end && step > 0) {
    472       return [];
    473     }
    474     if (step > 0) {
    475       for (i = start; i < end; i += step) {
    476         rl.push(list[i]);
    477       }
    478     } else {
    479       for (i = start; i > end;i += step) {
    480         rl.push(list[i]);
    481       }
    482     }
    483     return rl;
    484   }
    485 
    486   function slice(list, rcSlice) {
    487     var colSlice, rowSlice;
    488     rcSlice = rcSlice || {};
    489     if (isNumber(rcSlice.row)) {
    490       if (isNumber(rcSlice.col))
    491         return list[rcSlice.row][rcSlice.col];
    492       var row = jStat.rowa(list, rcSlice.row);
    493       colSlice = rcSlice.col || {};
    494       return _slice(row, colSlice.start, colSlice.end, colSlice.step);
    495     }
    496 
    497     if (isNumber(rcSlice.col)) {
    498       var col = jStat.cola(list, rcSlice.col);
    499       rowSlice = rcSlice.row || {};
    500       return _slice(col, rowSlice.start, rowSlice.end, rowSlice.step);
    501     }
    502 
    503     rowSlice = rcSlice.row || {};
    504     colSlice = rcSlice.col || {};
    505     var rows = _slice(list, rowSlice.start, rowSlice.end, rowSlice.step);
    506     return rows.map(function(row) {
    507       return _slice(row, colSlice.start, colSlice.end, colSlice.step);
    508     });
    509   }
    510 
    511   return slice;
    512 }());
    513 
    514 
    515 // A=[[1,2,3],[4,5,6],[7,8,9]]
    516 // sliceAssign(A,{row:{start:1},col:{start:1}},[[0,0],[0,0]])
    517 // A=[[1,2,3],[4,0,0],[7,0,0]]
    518 jStat.sliceAssign = function sliceAssign(A, rcSlice, B) {
    519   var nl, ml;
    520   if (isNumber(rcSlice.row)) {
    521     if (isNumber(rcSlice.col))
    522       return A[rcSlice.row][rcSlice.col] = B;
    523     rcSlice.col = rcSlice.col || {};
    524     rcSlice.col.start = rcSlice.col.start || 0;
    525     rcSlice.col.end = rcSlice.col.end || A[0].length;
    526     rcSlice.col.step = rcSlice.col.step || 1;
    527     nl = jStat.arange(rcSlice.col.start,
    528                           Math.min(A.length, rcSlice.col.end),
    529                           rcSlice.col.step);
    530     var m = rcSlice.row;
    531     nl.forEach(function(n, i) {
    532       A[m][n] = B[i];
    533     });
    534     return A;
    535   }
    536 
    537   if (isNumber(rcSlice.col)) {
    538     rcSlice.row = rcSlice.row || {};
    539     rcSlice.row.start = rcSlice.row.start || 0;
    540     rcSlice.row.end = rcSlice.row.end || A.length;
    541     rcSlice.row.step = rcSlice.row.step || 1;
    542     ml = jStat.arange(rcSlice.row.start,
    543                           Math.min(A[0].length, rcSlice.row.end),
    544                           rcSlice.row.step);
    545     var n = rcSlice.col;
    546     ml.forEach(function(m, j) {
    547       A[m][n] = B[j];
    548     });
    549     return A;
    550   }
    551 
    552   if (B[0].length === undefined) {
    553     B = [B];
    554   }
    555   rcSlice.row.start = rcSlice.row.start || 0;
    556   rcSlice.row.end = rcSlice.row.end || A.length;
    557   rcSlice.row.step = rcSlice.row.step || 1;
    558   rcSlice.col.start = rcSlice.col.start || 0;
    559   rcSlice.col.end = rcSlice.col.end || A[0].length;
    560   rcSlice.col.step = rcSlice.col.step || 1;
    561   ml = jStat.arange(rcSlice.row.start,
    562                         Math.min(A.length, rcSlice.row.end),
    563                         rcSlice.row.step);
    564   nl = jStat.arange(rcSlice.col.start,
    565                         Math.min(A[0].length, rcSlice.col.end),
    566                         rcSlice.col.step);
    567   ml.forEach(function(m, i) {
    568     nl.forEach(function(n, j) {
    569       A[m][n] = B[i][j];
    570     });
    571   });
    572   return A;
    573 };
    574 
    575 
    576 // [1,2,3] ->
    577 // [[1,0,0],[0,2,0],[0,0,3]]
    578 jStat.diagonal = function diagonal(diagArray) {
    579   var mat = jStat.zeros(diagArray.length, diagArray.length);
    580   diagArray.forEach(function(t, i) {
    581     mat[i][i] = t;
    582   });
    583   return mat;
    584 };
    585 
    586 
    587 // return copy of A
    588 jStat.copy = function copy(A) {
    589   return A.map(function(row) {
    590     if (isNumber(row))
    591       return row;
    592     return row.map(function(t) {
    593       return t;
    594     });
    595   });
    596 };
    597 
    598 
    599 // TODO: Go over this entire implementation. Seems a tragic waste of resources
    600 // doing all this work. Instead, and while ugly, use new Function() to generate
    601 // a custom function for each static method.
    602 
    603 // Quick reference.
    604 var jProto = jStat.prototype;
    605 
    606 // Default length.
    607 jProto.length = 0;
    608 
    609 // For internal use only.
    610 // TODO: Check if they're actually used, and if they are then rename them
    611 // to _*
    612 jProto.push = Array.prototype.push;
    613 jProto.sort = Array.prototype.sort;
    614 jProto.splice = Array.prototype.splice;
    615 jProto.slice = Array.prototype.slice;
    616 
    617 
    618 // Return a clean array.
    619 jProto.toArray = function toArray() {
    620   return this.length > 1 ? slice.call(this) : slice.call(this)[0];
    621 };
    622 
    623 
    624 // Map a function to a matrix or vector.
    625 jProto.map = function map(func, toAlter) {
    626   return jStat(jStat.map(this, func, toAlter));
    627 };
    628 
    629 
    630 // Cumulatively combine the elements of a matrix or vector using a function.
    631 jProto.cumreduce = function cumreduce(func, toAlter) {
    632   return jStat(jStat.cumreduce(this, func, toAlter));
    633 };
    634 
    635 
    636 // Destructively alter an array.
    637 jProto.alter = function alter(func) {
    638   jStat.alter(this, func);
    639   return this;
    640 };
    641 
    642 
    643 // Extend prototype with methods that have no argument.
    644 (function(funcs) {
    645   for (var i = 0; i < funcs.length; i++) (function(passfunc) {
    646     jProto[passfunc] = function(func) {
    647       var self = this,
    648       results;
    649       // Check for callback.
    650       if (func) {
    651         setTimeout(function() {
    652           func.call(self, jProto[passfunc].call(self));
    653         });
    654         return this;
    655       }
    656       results = jStat[passfunc](this);
    657       return isArray(results) ? jStat(results) : results;
    658     };
    659   })(funcs[i]);
    660 })('transpose clear symmetric rows cols dimensions diag antidiag'.split(' '));
    661 
    662 
    663 // Extend prototype with methods that have one argument.
    664 (function(funcs) {
    665   for (var i = 0; i < funcs.length; i++) (function(passfunc) {
    666     jProto[passfunc] = function(index, func) {
    667       var self = this;
    668       // check for callback
    669       if (func) {
    670         setTimeout(function() {
    671           func.call(self, jProto[passfunc].call(self, index));
    672         });
    673         return this;
    674       }
    675       return jStat(jStat[passfunc](this, index));
    676     };
    677   })(funcs[i]);
    678 })('row col'.split(' '));
    679 
    680 
    681 // Extend prototype with simple shortcut methods.
    682 (function(funcs) {
    683   for (var i = 0; i < funcs.length; i++) (function(passfunc) {
    684     jProto[passfunc] = function() {
    685       return jStat(jStat[passfunc].apply(null, arguments));
    686     };
    687   })(funcs[i]);
    688 })('create zeros ones rand identity'.split(' '));
    689 
    690 
    691 // Exposing jStat.
    692 return jStat;
    693 
    694 }(Math));
    695 (function(jStat, Math) {
    696 
    697 var isFunction = jStat.utils.isFunction;
    698 
    699 // Ascending functions for sort
    700 function ascNum(a, b) { return a - b; }
    701 
    702 function clip(arg, min, max) {
    703   return Math.max(min, Math.min(arg, max));
    704 }
    705 
    706 
    707 // sum of an array
    708 jStat.sum = function sum(arr) {
    709   var sum = 0;
    710   var i = arr.length;
    711   while (--i >= 0)
    712     sum += arr[i];
    713   return sum;
    714 };
    715 
    716 
    717 // sum squared
    718 jStat.sumsqrd = function sumsqrd(arr) {
    719   var sum = 0;
    720   var i = arr.length;
    721   while (--i >= 0)
    722     sum += arr[i] * arr[i];
    723   return sum;
    724 };
    725 
    726 
    727 // sum of squared errors of prediction (SSE)
    728 jStat.sumsqerr = function sumsqerr(arr) {
    729   var mean = jStat.mean(arr);
    730   var sum = 0;
    731   var i = arr.length;
    732   var tmp;
    733   while (--i >= 0) {
    734     tmp = arr[i] - mean;
    735     sum += tmp * tmp;
    736   }
    737   return sum;
    738 };
    739 
    740 // sum of an array in each row
    741 jStat.sumrow = function sumrow(arr) {
    742   var sum = 0;
    743   var i = arr.length;
    744   while (--i >= 0)
    745     sum += arr[i];
    746   return sum;
    747 };
    748 
    749 // product of an array
    750 jStat.product = function product(arr) {
    751   var prod = 1;
    752   var i = arr.length;
    753   while (--i >= 0)
    754     prod *= arr[i];
    755   return prod;
    756 };
    757 
    758 
    759 // minimum value of an array
    760 jStat.min = function min(arr) {
    761   var low = arr[0];
    762   var i = 0;
    763   while (++i < arr.length)
    764     if (arr[i] < low)
    765       low = arr[i];
    766   return low;
    767 };
    768 
    769 
    770 // maximum value of an array
    771 jStat.max = function max(arr) {
    772   var high = arr[0];
    773   var i = 0;
    774   while (++i < arr.length)
    775     if (arr[i] > high)
    776       high = arr[i];
    777   return high;
    778 };
    779 
    780 
    781 // unique values of an array
    782 jStat.unique = function unique(arr) {
    783   var hash = {}, _arr = [];
    784   for(var i = 0; i < arr.length; i++) {
    785     if (!hash[arr[i]]) {
    786       hash[arr[i]] = true;
    787       _arr.push(arr[i]);
    788     }
    789   }
    790   return _arr;
    791 };
    792 
    793 
    794 // mean value of an array
    795 jStat.mean = function mean(arr) {
    796   return jStat.sum(arr) / arr.length;
    797 };
    798 
    799 
    800 // mean squared error (MSE)
    801 jStat.meansqerr = function meansqerr(arr) {
    802   return jStat.sumsqerr(arr) / arr.length;
    803 };
    804 
    805 
    806 // geometric mean of an array
    807 jStat.geomean = function geomean(arr) {
    808   var logs = arr.map(Math.log)
    809   var meanOfLogs = jStat.mean(logs)
    810   return Math.exp(meanOfLogs)
    811 };
    812 
    813 
    814 // median of an array
    815 jStat.median = function median(arr) {
    816   var arrlen = arr.length;
    817   var _arr = arr.slice().sort(ascNum);
    818   // check if array is even or odd, then return the appropriate
    819   return !(arrlen & 1)
    820     ? (_arr[(arrlen / 2) - 1 ] + _arr[(arrlen / 2)]) / 2
    821     : _arr[(arrlen / 2) | 0 ];
    822 };
    823 
    824 
    825 // cumulative sum of an array
    826 jStat.cumsum = function cumsum(arr) {
    827   return jStat.cumreduce(arr, function (a, b) { return a + b; });
    828 };
    829 
    830 
    831 // cumulative product of an array
    832 jStat.cumprod = function cumprod(arr) {
    833   return jStat.cumreduce(arr, function (a, b) { return a * b; });
    834 };
    835 
    836 
    837 // successive differences of a sequence
    838 jStat.diff = function diff(arr) {
    839   var diffs = [];
    840   var arrLen = arr.length;
    841   var i;
    842   for (i = 1; i < arrLen; i++)
    843     diffs.push(arr[i] - arr[i - 1]);
    844   return diffs;
    845 };
    846 
    847 
    848 // ranks of an array
    849 jStat.rank = function (arr) {
    850   var i;
    851   var distinctNumbers = [];
    852   var numberCounts = {};
    853   for (i = 0; i < arr.length; i++) {
    854     var number = arr[i];
    855     if (numberCounts[number]) {
    856       numberCounts[number]++;
    857     } else {
    858       numberCounts[number] = 1;
    859       distinctNumbers.push(number);
    860     }
    861   }
    862 
    863   var sortedDistinctNumbers = distinctNumbers.sort(ascNum);
    864   var numberRanks = {};
    865   var currentRank = 1;
    866   for (i = 0; i < sortedDistinctNumbers.length; i++) {
    867     var number = sortedDistinctNumbers[i];
    868     var count = numberCounts[number];
    869     var first = currentRank;
    870     var last = currentRank + count - 1;
    871     var rank = (first + last) / 2;
    872     numberRanks[number] = rank;
    873     currentRank += count;
    874   }
    875 
    876   return arr.map(function (number) {
    877     return numberRanks[number];
    878   });
    879 };
    880 
    881 
    882 // mode of an array
    883 // if there are multiple modes of an array, return all of them
    884 // is this the appropriate way of handling it?
    885 jStat.mode = function mode(arr) {
    886   var arrLen = arr.length;
    887   var _arr = arr.slice().sort(ascNum);
    888   var count = 1;
    889   var maxCount = 0;
    890   var numMaxCount = 0;
    891   var mode_arr = [];
    892   var i;
    893 
    894   for (i = 0; i < arrLen; i++) {
    895     if (_arr[i] === _arr[i + 1]) {
    896       count++;
    897     } else {
    898       if (count > maxCount) {
    899         mode_arr = [_arr[i]];
    900         maxCount = count;
    901         numMaxCount = 0;
    902       }
    903       // are there multiple max counts
    904       else if (count === maxCount) {
    905         mode_arr.push(_arr[i]);
    906         numMaxCount++;
    907       }
    908       // resetting count for new value in array
    909       count = 1;
    910     }
    911   }
    912 
    913   return numMaxCount === 0 ? mode_arr[0] : mode_arr;
    914 };
    915 
    916 
    917 // range of an array
    918 jStat.range = function range(arr) {
    919   return jStat.max(arr) - jStat.min(arr);
    920 };
    921 
    922 // variance of an array
    923 // flag = true indicates sample instead of population
    924 jStat.variance = function variance(arr, flag) {
    925   return jStat.sumsqerr(arr) / (arr.length - (flag ? 1 : 0));
    926 };
    927 
    928 // pooled variance of an array of arrays
    929 jStat.pooledvariance = function pooledvariance(arr) {
    930   var sumsqerr = arr.reduce(function (a, samples) {return a + jStat.sumsqerr(samples);}, 0);
    931   var count = arr.reduce(function (a, samples) {return a + samples.length;}, 0);
    932   return sumsqerr / (count - arr.length);
    933 };
    934 
    935 // deviation of an array
    936 jStat.deviation = function (arr) {
    937   var mean = jStat.mean(arr);
    938   var arrlen = arr.length;
    939   var dev = new Array(arrlen);
    940   for (var i = 0; i < arrlen; i++) {
    941     dev[i] = arr[i] - mean;
    942   }
    943   return dev;
    944 };
    945 
    946 // standard deviation of an array
    947 // flag = true indicates sample instead of population
    948 jStat.stdev = function stdev(arr, flag) {
    949   return Math.sqrt(jStat.variance(arr, flag));
    950 };
    951 
    952 // pooled standard deviation of an array of arrays
    953 jStat.pooledstdev = function pooledstdev(arr) {
    954   return Math.sqrt(jStat.pooledvariance(arr));
    955 };
    956 
    957 // mean deviation (mean absolute deviation) of an array
    958 jStat.meandev = function meandev(arr) {
    959   var mean = jStat.mean(arr);
    960   var a = [];
    961   for (var i = arr.length - 1; i >= 0; i--) {
    962     a.push(Math.abs(arr[i] - mean));
    963   }
    964   return jStat.mean(a);
    965 };
    966 
    967 
    968 // median deviation (median absolute deviation) of an array
    969 jStat.meddev = function meddev(arr) {
    970   var median = jStat.median(arr);
    971   var a = [];
    972   for (var i = arr.length - 1; i >= 0; i--) {
    973     a.push(Math.abs(arr[i] - median));
    974   }
    975   return jStat.median(a);
    976 };
    977 
    978 
    979 // coefficient of variation
    980 jStat.coeffvar = function coeffvar(arr) {
    981   return jStat.stdev(arr) / jStat.mean(arr);
    982 };
    983 
    984 
    985 // quartiles of an array
    986 jStat.quartiles = function quartiles(arr) {
    987   var arrlen = arr.length;
    988   var _arr = arr.slice().sort(ascNum);
    989   return [
    990     _arr[ Math.round((arrlen) / 4) - 1 ],
    991     _arr[ Math.round((arrlen) / 2) - 1 ],
    992     _arr[ Math.round((arrlen) * 3 / 4) - 1 ]
    993   ];
    994 };
    995 
    996 
    997 // Arbitary quantiles of an array. Direct port of the scipy.stats
    998 // implementation by Pierre GF Gerard-Marchant.
    999 jStat.quantiles = function quantiles(arr, quantilesArray, alphap, betap) {
   1000   var sortedArray = arr.slice().sort(ascNum);
   1001   var quantileVals = [quantilesArray.length];
   1002   var n = arr.length;
   1003   var i, p, m, aleph, k, gamma;
   1004 
   1005   if (typeof alphap === 'undefined')
   1006     alphap = 3 / 8;
   1007   if (typeof betap === 'undefined')
   1008     betap = 3 / 8;
   1009 
   1010   for (i = 0; i < quantilesArray.length; i++) {
   1011     p = quantilesArray[i];
   1012     m = alphap + p * (1 - alphap - betap);
   1013     aleph = n * p + m;
   1014     k = Math.floor(clip(aleph, 1, n - 1));
   1015     gamma = clip(aleph - k, 0, 1);
   1016     quantileVals[i] = (1 - gamma) * sortedArray[k - 1] + gamma * sortedArray[k];
   1017   }
   1018 
   1019   return quantileVals;
   1020 };
   1021 
   1022 // Return the k-th percentile of values in a range, where k is in the range 0..1, inclusive.
   1023 // Passing true for the exclusive parameter excludes both endpoints of the range.
   1024 jStat.percentile = function percentile(arr, k, exclusive) {
   1025   var _arr = arr.slice().sort(ascNum);
   1026   var realIndex = k * (_arr.length + (exclusive ? 1 : -1)) + (exclusive ? 0 : 1);
   1027   var index = parseInt(realIndex);
   1028   var frac = realIndex - index;
   1029   if (index + 1 < _arr.length) {
   1030     return _arr[index - 1] + frac * (_arr[index] - _arr[index - 1]);
   1031   } else {
   1032     return _arr[index - 1];
   1033   }
   1034 }
   1035 
   1036 // The percentile rank of score in a given array. Returns the percentage
   1037 // of all values in the input array that are less than (kind='strict') or
   1038 // less or equal than (kind='weak') score. Default is weak.
   1039 jStat.percentileOfScore = function percentileOfScore(arr, score, kind) {
   1040   var counter = 0;
   1041   var len = arr.length;
   1042   var strict = false;
   1043   var value, i;
   1044 
   1045   if (kind === 'strict')
   1046     strict = true;
   1047 
   1048   for (i = 0; i < len; i++) {
   1049     value = arr[i];
   1050     if ((strict && value < score) ||
   1051         (!strict && value <= score)) {
   1052       counter++;
   1053     }
   1054   }
   1055 
   1056   return counter / len;
   1057 };
   1058 
   1059 
   1060 // Histogram (bin count) data
   1061 jStat.histogram = function histogram(arr, binCnt) {
   1062   binCnt = binCnt || 4;
   1063   var first = jStat.min(arr);
   1064   var binWidth = (jStat.max(arr) - first) / binCnt;
   1065   var len = arr.length;
   1066   var bins = [];
   1067   var i;
   1068 
   1069   for (i = 0; i < binCnt; i++)
   1070     bins[i] = 0;
   1071   for (i = 0; i < len; i++)
   1072     bins[Math.min(Math.floor(((arr[i] - first) / binWidth)), binCnt - 1)] += 1;
   1073 
   1074   return bins;
   1075 };
   1076 
   1077 
   1078 // covariance of two arrays
   1079 jStat.covariance = function covariance(arr1, arr2) {
   1080   var u = jStat.mean(arr1);
   1081   var v = jStat.mean(arr2);
   1082   var arr1Len = arr1.length;
   1083   var sq_dev = new Array(arr1Len);
   1084   var i;
   1085 
   1086   for (i = 0; i < arr1Len; i++)
   1087     sq_dev[i] = (arr1[i] - u) * (arr2[i] - v);
   1088 
   1089   return jStat.sum(sq_dev) / (arr1Len - 1);
   1090 };
   1091 
   1092 
   1093 // (pearson's) population correlation coefficient, rho
   1094 jStat.corrcoeff = function corrcoeff(arr1, arr2) {
   1095   return jStat.covariance(arr1, arr2) /
   1096       jStat.stdev(arr1, 1) /
   1097       jStat.stdev(arr2, 1);
   1098 };
   1099 
   1100   // (spearman's) rank correlation coefficient, sp
   1101 jStat.spearmancoeff =  function (arr1, arr2) {
   1102   arr1 = jStat.rank(arr1);
   1103   arr2 = jStat.rank(arr2);
   1104   //return pearson's correlation of the ranks:
   1105   return jStat.corrcoeff(arr1, arr2);
   1106 }
   1107 
   1108 
   1109 // statistical standardized moments (general form of skew/kurt)
   1110 jStat.stanMoment = function stanMoment(arr, n) {
   1111   var mu = jStat.mean(arr);
   1112   var sigma = jStat.stdev(arr);
   1113   var len = arr.length;
   1114   var skewSum = 0;
   1115 
   1116   for (var i = 0; i < len; i++)
   1117     skewSum += Math.pow((arr[i] - mu) / sigma, n);
   1118 
   1119   return skewSum / arr.length;
   1120 };
   1121 
   1122 // (pearson's) moment coefficient of skewness
   1123 jStat.skewness = function skewness(arr) {
   1124   return jStat.stanMoment(arr, 3);
   1125 };
   1126 
   1127 // (pearson's) (excess) kurtosis
   1128 jStat.kurtosis = function kurtosis(arr) {
   1129   return jStat.stanMoment(arr, 4) - 3;
   1130 };
   1131 
   1132 
   1133 var jProto = jStat.prototype;
   1134 
   1135 
   1136 // Extend jProto with method for calculating cumulative sums and products.
   1137 // This differs from the similar extension below as cumsum and cumprod should
   1138 // not be run again in the case fullbool === true.
   1139 // If a matrix is passed, automatically assume operation should be done on the
   1140 // columns.
   1141 (function(funcs) {
   1142   for (var i = 0; i < funcs.length; i++) (function(passfunc) {
   1143     // If a matrix is passed, automatically assume operation should be done on
   1144     // the columns.
   1145     jProto[passfunc] = function(fullbool, func) {
   1146       var arr = [];
   1147       var i = 0;
   1148       var tmpthis = this;
   1149       // Assignment reassignation depending on how parameters were passed in.
   1150       if (isFunction(fullbool)) {
   1151         func = fullbool;
   1152         fullbool = false;
   1153       }
   1154       // Check if a callback was passed with the function.
   1155       if (func) {
   1156         setTimeout(function() {
   1157           func.call(tmpthis, jProto[passfunc].call(tmpthis, fullbool));
   1158         });
   1159         return this;
   1160       }
   1161       // Check if matrix and run calculations.
   1162       if (this.length > 1) {
   1163         tmpthis = fullbool === true ? this : this.transpose();
   1164         for (; i < tmpthis.length; i++)
   1165           arr[i] = jStat[passfunc](tmpthis[i]);
   1166         return arr;
   1167       }
   1168       // Pass fullbool if only vector, not a matrix. for variance and stdev.
   1169       return jStat[passfunc](this[0], fullbool);
   1170     };
   1171   })(funcs[i]);
   1172 })(('cumsum cumprod').split(' '));
   1173 
   1174 
   1175 // Extend jProto with methods which don't require arguments and work on columns.
   1176 (function(funcs) {
   1177   for (var i = 0; i < funcs.length; i++) (function(passfunc) {
   1178     // If a matrix is passed, automatically assume operation should be done on
   1179     // the columns.
   1180     jProto[passfunc] = function(fullbool, func) {
   1181       var arr = [];
   1182       var i = 0;
   1183       var tmpthis = this;
   1184       // Assignment reassignation depending on how parameters were passed in.
   1185       if (isFunction(fullbool)) {
   1186         func = fullbool;
   1187         fullbool = false;
   1188       }
   1189       // Check if a callback was passed with the function.
   1190       if (func) {
   1191         setTimeout(function() {
   1192           func.call(tmpthis, jProto[passfunc].call(tmpthis, fullbool));
   1193         });
   1194         return this;
   1195       }
   1196       // Check if matrix and run calculations.
   1197       if (this.length > 1) {
   1198         if (passfunc !== 'sumrow')
   1199           tmpthis = fullbool === true ? this : this.transpose();
   1200         for (; i < tmpthis.length; i++)
   1201           arr[i] = jStat[passfunc](tmpthis[i]);
   1202         return fullbool === true
   1203             ? jStat[passfunc](jStat.utils.toVector(arr))
   1204             : arr;
   1205       }
   1206       // Pass fullbool if only vector, not a matrix. for variance and stdev.
   1207       return jStat[passfunc](this[0], fullbool);
   1208     };
   1209   })(funcs[i]);
   1210 })(('sum sumsqrd sumsqerr sumrow product min max unique mean meansqerr ' +
   1211     'geomean median diff rank mode range variance deviation stdev meandev ' +
   1212     'meddev coeffvar quartiles histogram skewness kurtosis').split(' '));
   1213 
   1214 
   1215 // Extend jProto with functions that take arguments. Operations on matrices are
   1216 // done on columns.
   1217 (function(funcs) {
   1218   for (var i = 0; i < funcs.length; i++) (function(passfunc) {
   1219     jProto[passfunc] = function() {
   1220       var arr = [];
   1221       var i = 0;
   1222       var tmpthis = this;
   1223       var args = Array.prototype.slice.call(arguments);
   1224       var callbackFunction;
   1225 
   1226       // If the last argument is a function, we assume it's a callback; we
   1227       // strip the callback out and call the function again.
   1228       if (isFunction(args[args.length - 1])) {
   1229         callbackFunction = args[args.length - 1];
   1230         var argsToPass = args.slice(0, args.length - 1);
   1231 
   1232         setTimeout(function() {
   1233           callbackFunction.call(tmpthis,
   1234                                 jProto[passfunc].apply(tmpthis, argsToPass));
   1235         });
   1236         return this;
   1237 
   1238       // Otherwise we curry the function args and call normally.
   1239       } else {
   1240         callbackFunction = undefined;
   1241         var curriedFunction = function curriedFunction(vector) {
   1242           return jStat[passfunc].apply(tmpthis, [vector].concat(args));
   1243         }
   1244       }
   1245 
   1246       // If this is a matrix, run column-by-column.
   1247       if (this.length > 1) {
   1248         tmpthis = tmpthis.transpose();
   1249         for (; i < tmpthis.length; i++)
   1250           arr[i] = curriedFunction(tmpthis[i]);
   1251         return arr;
   1252       }
   1253 
   1254       // Otherwise run on the vector.
   1255       return curriedFunction(this[0]);
   1256     };
   1257   })(funcs[i]);
   1258 })('quantiles percentileOfScore'.split(' '));
   1259 
   1260 }(jStat, Math));
   1261 // Special functions //
   1262 (function(jStat, Math) {
   1263 
   1264 // Log-gamma function
   1265 jStat.gammaln = function gammaln(x) {
   1266   var j = 0;
   1267   var cof = [
   1268     76.18009172947146, -86.50532032941677, 24.01409824083091,
   1269     -1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5
   1270   ];
   1271   var ser = 1.000000000190015;
   1272   var xx, y, tmp;
   1273   tmp = (y = xx = x) + 5.5;
   1274   tmp -= (xx + 0.5) * Math.log(tmp);
   1275   for (; j < 6; j++)
   1276     ser += cof[j] / ++y;
   1277   return Math.log(2.5066282746310005 * ser / xx) - tmp;
   1278 };
   1279 
   1280 /*
   1281  * log-gamma function to support poisson distribution sampling. The
   1282  * algorithm comes from SPECFUN by Shanjie Zhang and Jianming Jin and their
   1283  * book "Computation of Special Functions", 1996, John Wiley & Sons, Inc.
   1284  */
   1285 jStat.loggam = function loggam(x) {
   1286   var x0, x2, xp, gl, gl0;
   1287   var k, n;
   1288 
   1289   var a = [8.333333333333333e-02, -2.777777777777778e-03,
   1290           7.936507936507937e-04, -5.952380952380952e-04,
   1291           8.417508417508418e-04, -1.917526917526918e-03,
   1292           6.410256410256410e-03, -2.955065359477124e-02,
   1293           1.796443723688307e-01, -1.39243221690590e+00];
   1294   x0 = x;
   1295   n = 0;
   1296   if ((x == 1.0) || (x == 2.0)) {
   1297       return 0.0;
   1298   }
   1299   if (x <= 7.0) {
   1300       n = Math.floor(7 - x);
   1301       x0 = x + n;
   1302   }
   1303   x2 = 1.0 / (x0 * x0);
   1304   xp = 2 * Math.PI;
   1305   gl0 = a[9];
   1306   for (k = 8; k >= 0; k--) {
   1307       gl0 *= x2;
   1308       gl0 += a[k];
   1309   }
   1310   gl = gl0 / x0 + 0.5 * Math.log(xp) + (x0 - 0.5) * Math.log(x0) - x0;
   1311   if (x <= 7.0) {
   1312       for (k = 1; k <= n; k++) {
   1313           gl -= Math.log(x0 - 1.0);
   1314           x0 -= 1.0;
   1315       }
   1316   }
   1317   return gl;
   1318 }
   1319 
   1320 // gamma of x
   1321 jStat.gammafn = function gammafn(x) {
   1322   var p = [-1.716185138865495, 24.76565080557592, -379.80425647094563,
   1323            629.3311553128184, 866.9662027904133, -31451.272968848367,
   1324            -36144.413418691176, 66456.14382024054
   1325   ];
   1326   var q = [-30.8402300119739, 315.35062697960416, -1015.1563674902192,
   1327            -3107.771671572311, 22538.118420980151, 4755.8462775278811,
   1328            -134659.9598649693, -115132.2596755535];
   1329   var fact = false;
   1330   var n = 0;
   1331   var xden = 0;
   1332   var xnum = 0;
   1333   var y = x;
   1334   var i, z, yi, res;
   1335   if (x > 171.6243769536076) {
   1336     return Infinity;
   1337   }
   1338   if (y <= 0) {
   1339     res = y % 1 + 3.6e-16;
   1340     if (res) {
   1341       fact = (!(y & 1) ? 1 : -1) * Math.PI / Math.sin(Math.PI * res);
   1342       y = 1 - y;
   1343     } else {
   1344       return Infinity;
   1345     }
   1346   }
   1347   yi = y;
   1348   if (y < 1) {
   1349     z = y++;
   1350   } else {
   1351     z = (y -= n = (y | 0) - 1) - 1;
   1352   }
   1353   for (i = 0; i < 8; ++i) {
   1354     xnum = (xnum + p[i]) * z;
   1355     xden = xden * z + q[i];
   1356   }
   1357   res = xnum / xden + 1;
   1358   if (yi < y) {
   1359     res /= yi;
   1360   } else if (yi > y) {
   1361     for (i = 0; i < n; ++i) {
   1362       res *= y;
   1363       y++;
   1364     }
   1365   }
   1366   if (fact) {
   1367     res = fact / res;
   1368   }
   1369   return res;
   1370 };
   1371 
   1372 
   1373 // lower incomplete gamma function, which is usually typeset with a
   1374 // lower-case greek gamma as the function symbol
   1375 jStat.gammap = function gammap(a, x) {
   1376   return jStat.lowRegGamma(a, x) * jStat.gammafn(a);
   1377 };
   1378 
   1379 
   1380 // The lower regularized incomplete gamma function, usually written P(a,x)
   1381 jStat.lowRegGamma = function lowRegGamma(a, x) {
   1382   var aln = jStat.gammaln(a);
   1383   var ap = a;
   1384   var sum = 1 / a;
   1385   var del = sum;
   1386   var b = x + 1 - a;
   1387   var c = 1 / 1.0e-30;
   1388   var d = 1 / b;
   1389   var h = d;
   1390   var i = 1;
   1391   // calculate maximum number of itterations required for a
   1392   var ITMAX = -~(Math.log((a >= 1) ? a : 1 / a) * 8.5 + a * 0.4 + 17);
   1393   var an;
   1394 
   1395   if (x < 0 || a <= 0) {
   1396     return NaN;
   1397   } else if (x < a + 1) {
   1398     for (; i <= ITMAX; i++) {
   1399       sum += del *= x / ++ap;
   1400     }
   1401     return (sum * Math.exp(-x + a * Math.log(x) - (aln)));
   1402   }
   1403 
   1404   for (; i <= ITMAX; i++) {
   1405     an = -i * (i - a);
   1406     b += 2;
   1407     d = an * d + b;
   1408     c = b + an / c;
   1409     d = 1 / d;
   1410     h *= d * c;
   1411   }
   1412 
   1413   return (1 - h * Math.exp(-x + a * Math.log(x) - (aln)));
   1414 };
   1415 
   1416 // natural log factorial of n
   1417 jStat.factorialln = function factorialln(n) {
   1418   return n < 0 ? NaN : jStat.gammaln(n + 1);
   1419 };
   1420 
   1421 // factorial of n
   1422 jStat.factorial = function factorial(n) {
   1423   return n < 0 ? NaN : jStat.gammafn(n + 1);
   1424 };
   1425 
   1426 // combinations of n, m
   1427 jStat.combination = function combination(n, m) {
   1428   // make sure n or m don't exceed the upper limit of usable values
   1429   return (n > 170 || m > 170)
   1430       ? Math.exp(jStat.combinationln(n, m))
   1431       : (jStat.factorial(n) / jStat.factorial(m)) / jStat.factorial(n - m);
   1432 };
   1433 
   1434 
   1435 jStat.combinationln = function combinationln(n, m){
   1436   return jStat.factorialln(n) - jStat.factorialln(m) - jStat.factorialln(n - m);
   1437 };
   1438 
   1439 
   1440 // permutations of n, m
   1441 jStat.permutation = function permutation(n, m) {
   1442   return jStat.factorial(n) / jStat.factorial(n - m);
   1443 };
   1444 
   1445 
   1446 // beta function
   1447 jStat.betafn = function betafn(x, y) {
   1448   // ensure arguments are positive
   1449   if (x <= 0 || y <= 0)
   1450     return undefined;
   1451   // make sure x + y doesn't exceed the upper limit of usable values
   1452   return (x + y > 170)
   1453       ? Math.exp(jStat.betaln(x, y))
   1454       : jStat.gammafn(x) * jStat.gammafn(y) / jStat.gammafn(x + y);
   1455 };
   1456 
   1457 
   1458 // natural logarithm of beta function
   1459 jStat.betaln = function betaln(x, y) {
   1460   return jStat.gammaln(x) + jStat.gammaln(y) - jStat.gammaln(x + y);
   1461 };
   1462 
   1463 
   1464 // Evaluates the continued fraction for incomplete beta function by modified
   1465 // Lentz's method.
   1466 jStat.betacf = function betacf(x, a, b) {
   1467   var fpmin = 1e-30;
   1468   var m = 1;
   1469   var qab = a + b;
   1470   var qap = a + 1;
   1471   var qam = a - 1;
   1472   var c = 1;
   1473   var d = 1 - qab * x / qap;
   1474   var m2, aa, del, h;
   1475 
   1476   // These q's will be used in factors that occur in the coefficients
   1477   if (Math.abs(d) < fpmin)
   1478     d = fpmin;
   1479   d = 1 / d;
   1480   h = d;
   1481 
   1482   for (; m <= 100; m++) {
   1483     m2 = 2 * m;
   1484     aa = m * (b - m) * x / ((qam + m2) * (a + m2));
   1485     // One step (the even one) of the recurrence
   1486     d = 1 + aa * d;
   1487     if (Math.abs(d) < fpmin)
   1488       d = fpmin;
   1489     c = 1 + aa / c;
   1490     if (Math.abs(c) < fpmin)
   1491       c = fpmin;
   1492     d = 1 / d;
   1493     h *= d * c;
   1494     aa = -(a + m) * (qab + m) * x / ((a + m2) * (qap + m2));
   1495     // Next step of the recurrence (the odd one)
   1496     d = 1 + aa * d;
   1497     if (Math.abs(d) < fpmin)
   1498       d = fpmin;
   1499     c = 1 + aa / c;
   1500     if (Math.abs(c) < fpmin)
   1501       c = fpmin;
   1502     d = 1 / d;
   1503     del = d * c;
   1504     h *= del;
   1505     if (Math.abs(del - 1.0) < 3e-7)
   1506       break;
   1507   }
   1508 
   1509   return h;
   1510 };
   1511 
   1512 
   1513 // Returns the inverse of the lower regularized inomplete gamma function
   1514 jStat.gammapinv = function gammapinv(p, a) {
   1515   var j = 0;
   1516   var a1 = a - 1;
   1517   var EPS = 1e-8;
   1518   var gln = jStat.gammaln(a);
   1519   var x, err, t, u, pp, lna1, afac;
   1520 
   1521   if (p >= 1)
   1522     return Math.max(100, a + 100 * Math.sqrt(a));
   1523   if (p <= 0)
   1524     return 0;
   1525   if (a > 1) {
   1526     lna1 = Math.log(a1);
   1527     afac = Math.exp(a1 * (lna1 - 1) - gln);
   1528     pp = (p < 0.5) ? p : 1 - p;
   1529     t = Math.sqrt(-2 * Math.log(pp));
   1530     x = (2.30753 + t * 0.27061) / (1 + t * (0.99229 + t * 0.04481)) - t;
   1531     if (p < 0.5)
   1532       x = -x;
   1533     x = Math.max(1e-3,
   1534                  a * Math.pow(1 - 1 / (9 * a) - x / (3 * Math.sqrt(a)), 3));
   1535   } else {
   1536     t = 1 - a * (0.253 + a * 0.12);
   1537     if (p < t)
   1538       x = Math.pow(p / t, 1 / a);
   1539     else
   1540       x = 1 - Math.log(1 - (p - t) / (1 - t));
   1541   }
   1542 
   1543   for(; j < 12; j++) {
   1544     if (x <= 0)
   1545       return 0;
   1546     err = jStat.lowRegGamma(a, x) - p;
   1547     if (a > 1)
   1548       t = afac * Math.exp(-(x - a1) + a1 * (Math.log(x) - lna1));
   1549     else
   1550       t = Math.exp(-x + a1 * Math.log(x) - gln);
   1551     u = err / t;
   1552     x -= (t = u / (1 - 0.5 * Math.min(1, u * ((a - 1) / x - 1))));
   1553     if (x <= 0)
   1554       x = 0.5 * (x + t);
   1555     if (Math.abs(t) < EPS * x)
   1556       break;
   1557   }
   1558 
   1559   return x;
   1560 };
   1561 
   1562 
   1563 // Returns the error function erf(x)
   1564 jStat.erf = function erf(x) {
   1565   var cof = [-1.3026537197817094, 6.4196979235649026e-1, 1.9476473204185836e-2,
   1566              -9.561514786808631e-3, -9.46595344482036e-4, 3.66839497852761e-4,
   1567              4.2523324806907e-5, -2.0278578112534e-5, -1.624290004647e-6,
   1568              1.303655835580e-6, 1.5626441722e-8, -8.5238095915e-8,
   1569              6.529054439e-9, 5.059343495e-9, -9.91364156e-10,
   1570              -2.27365122e-10, 9.6467911e-11, 2.394038e-12,
   1571              -6.886027e-12, 8.94487e-13, 3.13092e-13,
   1572              -1.12708e-13, 3.81e-16, 7.106e-15,
   1573              -1.523e-15, -9.4e-17, 1.21e-16,
   1574              -2.8e-17];
   1575   var j = cof.length - 1;
   1576   var isneg = false;
   1577   var d = 0;
   1578   var dd = 0;
   1579   var t, ty, tmp, res;
   1580 
   1581   if (x < 0) {
   1582     x = -x;
   1583     isneg = true;
   1584   }
   1585 
   1586   t = 2 / (2 + x);
   1587   ty = 4 * t - 2;
   1588 
   1589   for(; j > 0; j--) {
   1590     tmp = d;
   1591     d = ty * d - dd + cof[j];
   1592     dd = tmp;
   1593   }
   1594 
   1595   res = t * Math.exp(-x * x + 0.5 * (cof[0] + ty * d) - dd);
   1596   return isneg ? res - 1 : 1 - res;
   1597 };
   1598 
   1599 
   1600 // Returns the complmentary error function erfc(x)
   1601 jStat.erfc = function erfc(x) {
   1602   return 1 - jStat.erf(x);
   1603 };
   1604 
   1605 
   1606 // Returns the inverse of the complementary error function
   1607 jStat.erfcinv = function erfcinv(p) {
   1608   var j = 0;
   1609   var x, err, t, pp;
   1610   if (p >= 2)
   1611     return -100;
   1612   if (p <= 0)
   1613     return 100;
   1614   pp = (p < 1) ? p : 2 - p;
   1615   t = Math.sqrt(-2 * Math.log(pp / 2));
   1616   x = -0.70711 * ((2.30753 + t * 0.27061) /
   1617                   (1 + t * (0.99229 + t * 0.04481)) - t);
   1618   for (; j < 2; j++) {
   1619     err = jStat.erfc(x) - pp;
   1620     x += err / (1.12837916709551257 * Math.exp(-x * x) - x * err);
   1621   }
   1622   return (p < 1) ? x : -x;
   1623 };
   1624 
   1625 
   1626 // Returns the inverse of the incomplete beta function
   1627 jStat.ibetainv = function ibetainv(p, a, b) {
   1628   var EPS = 1e-8;
   1629   var a1 = a - 1;
   1630   var b1 = b - 1;
   1631   var j = 0;
   1632   var lna, lnb, pp, t, u, err, x, al, h, w, afac;
   1633   if (p <= 0)
   1634     return 0;
   1635   if (p >= 1)
   1636     return 1;
   1637   if (a >= 1 && b >= 1) {
   1638     pp = (p < 0.5) ? p : 1 - p;
   1639     t = Math.sqrt(-2 * Math.log(pp));
   1640     x = (2.30753 + t * 0.27061) / (1 + t* (0.99229 + t * 0.04481)) - t;
   1641     if (p < 0.5)
   1642       x = -x;
   1643     al = (x * x - 3) / 6;
   1644     h = 2 / (1 / (2 * a - 1)  + 1 / (2 * b - 1));
   1645     w = (x * Math.sqrt(al + h) / h) - (1 / (2 * b - 1) - 1 / (2 * a - 1)) *
   1646         (al + 5 / 6 - 2 / (3 * h));
   1647     x = a / (a + b * Math.exp(2 * w));
   1648   } else {
   1649     lna = Math.log(a / (a + b));
   1650     lnb = Math.log(b / (a + b));
   1651     t = Math.exp(a * lna) / a;
   1652     u = Math.exp(b * lnb) / b;
   1653     w = t + u;
   1654     if (p < t / w)
   1655       x = Math.pow(a * w * p, 1 / a);
   1656     else
   1657       x = 1 - Math.pow(b * w * (1 - p), 1 / b);
   1658   }
   1659   afac = -jStat.gammaln(a) - jStat.gammaln(b) + jStat.gammaln(a + b);
   1660   for(; j < 10; j++) {
   1661     if (x === 0 || x === 1)
   1662       return x;
   1663     err = jStat.ibeta(x, a, b) - p;
   1664     t = Math.exp(a1 * Math.log(x) + b1 * Math.log(1 - x) + afac);
   1665     u = err / t;
   1666     x -= (t = u / (1 - 0.5 * Math.min(1, u * (a1 / x - b1 / (1 - x)))));
   1667     if (x <= 0)
   1668       x = 0.5 * (x + t);
   1669     if (x >= 1)
   1670       x = 0.5 * (x + t + 1);
   1671     if (Math.abs(t) < EPS * x && j > 0)
   1672       break;
   1673   }
   1674   return x;
   1675 };
   1676 
   1677 
   1678 // Returns the incomplete beta function I_x(a,b)
   1679 jStat.ibeta = function ibeta(x, a, b) {
   1680   // Factors in front of the continued fraction.
   1681   var bt = (x === 0 || x === 1) ?  0 :
   1682     Math.exp(jStat.gammaln(a + b) - jStat.gammaln(a) -
   1683              jStat.gammaln(b) + a * Math.log(x) + b *
   1684              Math.log(1 - x));
   1685   if (x < 0 || x > 1)
   1686     return false;
   1687   if (x < (a + 1) / (a + b + 2))
   1688     // Use continued fraction directly.
   1689     return bt * jStat.betacf(x, a, b) / a;
   1690   // else use continued fraction after making the symmetry transformation.
   1691   return 1 - bt * jStat.betacf(1 - x, b, a) / b;
   1692 };
   1693 
   1694 
   1695 // Returns a normal deviate (mu=0, sigma=1).
   1696 // If n and m are specified it returns a object of normal deviates.
   1697 jStat.randn = function randn(n, m) {
   1698   var u, v, x, y, q;
   1699   if (!m)
   1700     m = n;
   1701   if (n)
   1702     return jStat.create(n, m, function() { return jStat.randn(); });
   1703   do {
   1704     u = jStat._random_fn();
   1705     v = 1.7156 * (jStat._random_fn() - 0.5);
   1706     x = u - 0.449871;
   1707     y = Math.abs(v) + 0.386595;
   1708     q = x * x + y * (0.19600 * y - 0.25472 * x);
   1709   } while (q > 0.27597 && (q > 0.27846 || v * v > -4 * Math.log(u) * u * u));
   1710   return v / u;
   1711 };
   1712 
   1713 
   1714 // Returns a gamma deviate by the method of Marsaglia and Tsang.
   1715 jStat.randg = function randg(shape, n, m) {
   1716   var oalph = shape;
   1717   var a1, a2, u, v, x, mat;
   1718   if (!m)
   1719     m = n;
   1720   if (!shape)
   1721     shape = 1;
   1722   if (n) {
   1723     mat = jStat.zeros(n,m);
   1724     mat.alter(function() { return jStat.randg(shape); });
   1725     return mat;
   1726   }
   1727   if (shape < 1)
   1728     shape += 1;
   1729   a1 = shape - 1 / 3;
   1730   a2 = 1 / Math.sqrt(9 * a1);
   1731   do {
   1732     do {
   1733       x = jStat.randn();
   1734       v = 1 + a2 * x;
   1735     } while(v <= 0);
   1736     v = v * v * v;
   1737     u = jStat._random_fn();
   1738   } while(u > 1 - 0.331 * Math.pow(x, 4) &&
   1739           Math.log(u) > 0.5 * x*x + a1 * (1 - v + Math.log(v)));
   1740   // alpha > 1
   1741   if (shape == oalph)
   1742     return a1 * v;
   1743   // alpha < 1
   1744   do {
   1745     u = jStat._random_fn();
   1746   } while(u === 0);
   1747   return Math.pow(u, 1 / oalph) * a1 * v;
   1748 };
   1749 
   1750 
   1751 // making use of static methods on the instance
   1752 (function(funcs) {
   1753   for (var i = 0; i < funcs.length; i++) (function(passfunc) {
   1754     jStat.fn[passfunc] = function() {
   1755       return jStat(
   1756           jStat.map(this, function(value) { return jStat[passfunc](value); }));
   1757     }
   1758   })(funcs[i]);
   1759 })('gammaln gammafn factorial factorialln'.split(' '));
   1760 
   1761 
   1762 (function(funcs) {
   1763   for (var i = 0; i < funcs.length; i++) (function(passfunc) {
   1764     jStat.fn[passfunc] = function() {
   1765       return jStat(jStat[passfunc].apply(null, arguments));
   1766     };
   1767   })(funcs[i]);
   1768 })('randn'.split(' '));
   1769 
   1770 }(jStat, Math));
   1771 (function(jStat, Math) {
   1772 
   1773 // generate all distribution instance methods
   1774 (function(list) {
   1775   for (var i = 0; i < list.length; i++) (function(func) {
   1776     // distribution instance method
   1777     jStat[func] = function f(a, b, c) {
   1778       if (!(this instanceof f))
   1779         return new f(a, b, c);
   1780       this._a = a;
   1781       this._b = b;
   1782       this._c = c;
   1783       return this;
   1784     };
   1785     // distribution method to be used on a jStat instance
   1786     jStat.fn[func] = function(a, b, c) {
   1787       var newthis = jStat[func](a, b, c);
   1788       newthis.data = this;
   1789       return newthis;
   1790     };
   1791     // sample instance method
   1792     jStat[func].prototype.sample = function(arr) {
   1793       var a = this._a;
   1794       var b = this._b;
   1795       var c = this._c;
   1796       if (arr)
   1797         return jStat.alter(arr, function() {
   1798           return jStat[func].sample(a, b, c);
   1799         });
   1800       else
   1801         return jStat[func].sample(a, b, c);
   1802     };
   1803     // generate the pdf, cdf and inv instance methods
   1804     (function(vals) {
   1805       for (var i = 0; i < vals.length; i++) (function(fnfunc) {
   1806         jStat[func].prototype[fnfunc] = function(x) {
   1807           var a = this._a;
   1808           var b = this._b;
   1809           var c = this._c;
   1810           if (!x && x !== 0)
   1811             x = this.data;
   1812           if (typeof x !== 'number') {
   1813             return jStat.fn.map.call(x, function(x) {
   1814               return jStat[func][fnfunc](x, a, b, c);
   1815             });
   1816           }
   1817           return jStat[func][fnfunc](x, a, b, c);
   1818         };
   1819       })(vals[i]);
   1820     })('pdf cdf inv'.split(' '));
   1821     // generate the mean, median, mode and variance instance methods
   1822     (function(vals) {
   1823       for (var i = 0; i < vals.length; i++) (function(fnfunc) {
   1824         jStat[func].prototype[fnfunc] = function() {
   1825           return jStat[func][fnfunc](this._a, this._b, this._c);
   1826         };
   1827       })(vals[i]);
   1828     })('mean median mode variance'.split(' '));
   1829   })(list[i]);
   1830 })((
   1831   'beta centralF cauchy chisquare exponential gamma invgamma kumaraswamy ' +
   1832   'laplace lognormal noncentralt normal pareto studentt weibull uniform ' +
   1833   'binomial negbin hypgeom poisson triangular tukey arcsine'
   1834 ).split(' '));
   1835 
   1836 
   1837 
   1838 // extend beta function with static methods
   1839 jStat.extend(jStat.beta, {
   1840   pdf: function pdf(x, alpha, beta) {
   1841     // PDF is zero outside the support
   1842     if (x > 1 || x < 0)
   1843       return 0;
   1844     // PDF is one for the uniform case
   1845     if (alpha == 1 && beta == 1)
   1846       return 1;
   1847 
   1848     if (alpha < 512 && beta < 512) {
   1849       return (Math.pow(x, alpha - 1) * Math.pow(1 - x, beta - 1)) /
   1850           jStat.betafn(alpha, beta);
   1851     } else {
   1852       return Math.exp((alpha - 1) * Math.log(x) +
   1853                       (beta - 1) * Math.log(1 - x) -
   1854                       jStat.betaln(alpha, beta));
   1855     }
   1856   },
   1857 
   1858   cdf: function cdf(x, alpha, beta) {
   1859     return (x > 1 || x < 0) ? (x > 1) * 1 : jStat.ibeta(x, alpha, beta);
   1860   },
   1861 
   1862   inv: function inv(x, alpha, beta) {
   1863     return jStat.ibetainv(x, alpha, beta);
   1864   },
   1865 
   1866   mean: function mean(alpha, beta) {
   1867     return alpha / (alpha + beta);
   1868   },
   1869 
   1870   median: function median(alpha, beta) {
   1871     return jStat.ibetainv(0.5, alpha, beta);
   1872   },
   1873 
   1874   mode: function mode(alpha, beta) {
   1875     return (alpha - 1 ) / ( alpha + beta - 2);
   1876   },
   1877 
   1878   // return a random sample
   1879   sample: function sample(alpha, beta) {
   1880     var u = jStat.randg(alpha);
   1881     return u / (u + jStat.randg(beta));
   1882   },
   1883 
   1884   variance: function variance(alpha, beta) {
   1885     return (alpha * beta) / (Math.pow(alpha + beta, 2) * (alpha + beta + 1));
   1886   }
   1887 });
   1888 
   1889 // extend F function with static methods
   1890 jStat.extend(jStat.centralF, {
   1891   // This implementation of the pdf function avoids float overflow
   1892   // See the way that R calculates this value:
   1893   // https://svn.r-project.org/R/trunk/src/nmath/df.c
   1894   pdf: function pdf(x, df1, df2) {
   1895     var p, q, f;
   1896 
   1897     if (x < 0)
   1898       return 0;
   1899 
   1900     if (df1 <= 2) {
   1901       if (x === 0 && df1 < 2) {
   1902         return Infinity;
   1903       }
   1904       if (x === 0 && df1 === 2) {
   1905         return 1;
   1906       }
   1907       return (1 / jStat.betafn(df1 / 2, df2 / 2)) *
   1908               Math.pow(df1 / df2, df1 / 2) *
   1909               Math.pow(x, (df1/2) - 1) *
   1910               Math.pow((1 + (df1 / df2) * x), -(df1 + df2) / 2);
   1911     }
   1912 
   1913     p = (df1 * x) / (df2 + x * df1);
   1914     q = df2 / (df2 + x * df1);
   1915     f = df1 * q / 2.0;
   1916     return f * jStat.binomial.pdf((df1 - 2) / 2, (df1 + df2 - 2) / 2, p);
   1917   },
   1918 
   1919   cdf: function cdf(x, df1, df2) {
   1920     if (x < 0)
   1921       return 0;
   1922     return jStat.ibeta((df1 * x) / (df1 * x + df2), df1 / 2, df2 / 2);
   1923   },
   1924 
   1925   inv: function inv(x, df1, df2) {
   1926     return df2 / (df1 * (1 / jStat.ibetainv(x, df1 / 2, df2 / 2) - 1));
   1927   },
   1928 
   1929   mean: function mean(df1, df2) {
   1930     return (df2 > 2) ? df2 / (df2 - 2) : undefined;
   1931   },
   1932 
   1933   mode: function mode(df1, df2) {
   1934     return (df1 > 2) ? (df2 * (df1 - 2)) / (df1 * (df2 + 2)) : undefined;
   1935   },
   1936 
   1937   // return a random sample
   1938   sample: function sample(df1, df2) {
   1939     var x1 = jStat.randg(df1 / 2) * 2;
   1940     var x2 = jStat.randg(df2 / 2) * 2;
   1941     return (x1 / df1) / (x2 / df2);
   1942   },
   1943 
   1944   variance: function variance(df1, df2) {
   1945     if (df2 <= 4)
   1946       return undefined;
   1947     return 2 * df2 * df2 * (df1 + df2 - 2) /
   1948         (df1 * (df2 - 2) * (df2 - 2) * (df2 - 4));
   1949   }
   1950 });
   1951 
   1952 
   1953 // extend cauchy function with static methods
   1954 jStat.extend(jStat.cauchy, {
   1955   pdf: function pdf(x, local, scale) {
   1956     if (scale < 0) { return 0; }
   1957 
   1958     return (scale / (Math.pow(x - local, 2) + Math.pow(scale, 2))) / Math.PI;
   1959   },
   1960 
   1961   cdf: function cdf(x, local, scale) {
   1962     return Math.atan((x - local) / scale) / Math.PI + 0.5;
   1963   },
   1964 
   1965   inv: function(p, local, scale) {
   1966     return local + scale * Math.tan(Math.PI * (p - 0.5));
   1967   },
   1968 
   1969   median: function median(local/*, scale*/) {
   1970     return local;
   1971   },
   1972 
   1973   mode: function mode(local/*, scale*/) {
   1974     return local;
   1975   },
   1976 
   1977   sample: function sample(local, scale) {
   1978     return jStat.randn() *
   1979         Math.sqrt(1 / (2 * jStat.randg(0.5))) * scale + local;
   1980   }
   1981 });
   1982 
   1983 
   1984 
   1985 // extend chisquare function with static methods
   1986 jStat.extend(jStat.chisquare, {
   1987   pdf: function pdf(x, dof) {
   1988     if (x < 0)
   1989       return 0;
   1990     return (x === 0 && dof === 2) ? 0.5 :
   1991         Math.exp((dof / 2 - 1) * Math.log(x) - x / 2 - (dof / 2) *
   1992                  Math.log(2) - jStat.gammaln(dof / 2));
   1993   },
   1994 
   1995   cdf: function cdf(x, dof) {
   1996     if (x < 0)
   1997       return 0;
   1998     return jStat.lowRegGamma(dof / 2, x / 2);
   1999   },
   2000 
   2001   inv: function(p, dof) {
   2002     return 2 * jStat.gammapinv(p, 0.5 * dof);
   2003   },
   2004 
   2005   mean : function(dof) {
   2006     return dof;
   2007   },
   2008 
   2009   // TODO: this is an approximation (is there a better way?)
   2010   median: function median(dof) {
   2011     return dof * Math.pow(1 - (2 / (9 * dof)), 3);
   2012   },
   2013 
   2014   mode: function mode(dof) {
   2015     return (dof - 2 > 0) ? dof - 2 : 0;
   2016   },
   2017 
   2018   sample: function sample(dof) {
   2019     return jStat.randg(dof / 2) * 2;
   2020   },
   2021 
   2022   variance: function variance(dof) {
   2023     return 2 * dof;
   2024   }
   2025 });
   2026 
   2027 
   2028 
   2029 // extend exponential function with static methods
   2030 jStat.extend(jStat.exponential, {
   2031   pdf: function pdf(x, rate) {
   2032     return x < 0 ? 0 : rate * Math.exp(-rate * x);
   2033   },
   2034 
   2035   cdf: function cdf(x, rate) {
   2036     return x < 0 ? 0 : 1 - Math.exp(-rate * x);
   2037   },
   2038 
   2039   inv: function(p, rate) {
   2040     return -Math.log(1 - p) / rate;
   2041   },
   2042 
   2043   mean : function(rate) {
   2044     return 1 / rate;
   2045   },
   2046 
   2047   median: function (rate) {
   2048     return (1 / rate) * Math.log(2);
   2049   },
   2050 
   2051   mode: function mode(/*rate*/) {
   2052     return 0;
   2053   },
   2054 
   2055   sample: function sample(rate) {
   2056     return -1 / rate * Math.log(jStat._random_fn());
   2057   },
   2058 
   2059   variance : function(rate) {
   2060     return Math.pow(rate, -2);
   2061   }
   2062 });
   2063 
   2064 
   2065 
   2066 // extend gamma function with static methods
   2067 jStat.extend(jStat.gamma, {
   2068   pdf: function pdf(x, shape, scale) {
   2069     if (x < 0)
   2070       return 0;
   2071     return (x === 0 && shape === 1) ? 1 / scale :
   2072             Math.exp((shape - 1) * Math.log(x) - x / scale -
   2073                     jStat.gammaln(shape) - shape * Math.log(scale));
   2074   },
   2075 
   2076   cdf: function cdf(x, shape, scale) {
   2077     if (x < 0)
   2078       return 0;
   2079     return jStat.lowRegGamma(shape, x / scale);
   2080   },
   2081 
   2082   inv: function(p, shape, scale) {
   2083     return jStat.gammapinv(p, shape) * scale;
   2084   },
   2085 
   2086   mean : function(shape, scale) {
   2087     return shape * scale;
   2088   },
   2089 
   2090   mode: function mode(shape, scale) {
   2091     if(shape > 1) return (shape - 1) * scale;
   2092     return undefined;
   2093   },
   2094 
   2095   sample: function sample(shape, scale) {
   2096     return jStat.randg(shape) * scale;
   2097   },
   2098 
   2099   variance: function variance(shape, scale) {
   2100     return shape * scale * scale;
   2101   }
   2102 });
   2103 
   2104 // extend inverse gamma function with static methods
   2105 jStat.extend(jStat.invgamma, {
   2106   pdf: function pdf(x, shape, scale) {
   2107     if (x <= 0)
   2108       return 0;
   2109     return Math.exp(-(shape + 1) * Math.log(x) - scale / x -
   2110                     jStat.gammaln(shape) + shape * Math.log(scale));
   2111   },
   2112 
   2113   cdf: function cdf(x, shape, scale) {
   2114     if (x <= 0)
   2115       return 0;
   2116     return 1 - jStat.lowRegGamma(shape, scale / x);
   2117   },
   2118 
   2119   inv: function(p, shape, scale) {
   2120     return scale / jStat.gammapinv(1 - p, shape);
   2121   },
   2122 
   2123   mean : function(shape, scale) {
   2124     return (shape > 1) ? scale / (shape - 1) : undefined;
   2125   },
   2126 
   2127   mode: function mode(shape, scale) {
   2128     return scale / (shape + 1);
   2129   },
   2130 
   2131   sample: function sample(shape, scale) {
   2132     return scale / jStat.randg(shape);
   2133   },
   2134 
   2135   variance: function variance(shape, scale) {
   2136     if (shape <= 2)
   2137       return undefined;
   2138     return scale * scale / ((shape - 1) * (shape - 1) * (shape - 2));
   2139   }
   2140 });
   2141 
   2142 
   2143 // extend kumaraswamy function with static methods
   2144 jStat.extend(jStat.kumaraswamy, {
   2145   pdf: function pdf(x, alpha, beta) {
   2146     if (x === 0 && alpha === 1)
   2147       return beta;
   2148     else if (x === 1 && beta === 1)
   2149       return alpha;
   2150     return Math.exp(Math.log(alpha) + Math.log(beta) + (alpha - 1) *
   2151                     Math.log(x) + (beta - 1) *
   2152                     Math.log(1 - Math.pow(x, alpha)));
   2153   },
   2154 
   2155   cdf: function cdf(x, alpha, beta) {
   2156     if (x < 0)
   2157       return 0;
   2158     else if (x > 1)
   2159       return 1;
   2160     return (1 - Math.pow(1 - Math.pow(x, alpha), beta));
   2161   },
   2162 
   2163   inv: function inv(p, alpha, beta) {
   2164     return Math.pow(1 - Math.pow(1 - p, 1 / beta), 1 / alpha);
   2165   },
   2166 
   2167   mean : function(alpha, beta) {
   2168     return (beta * jStat.gammafn(1 + 1 / alpha) *
   2169             jStat.gammafn(beta)) / (jStat.gammafn(1 + 1 / alpha + beta));
   2170   },
   2171 
   2172   median: function median(alpha, beta) {
   2173     return Math.pow(1 - Math.pow(2, -1 / beta), 1 / alpha);
   2174   },
   2175 
   2176   mode: function mode(alpha, beta) {
   2177     if (!(alpha >= 1 && beta >= 1 && (alpha !== 1 && beta !== 1)))
   2178       return undefined;
   2179     return Math.pow((alpha - 1) / (alpha * beta - 1), 1 / alpha);
   2180   },
   2181 
   2182   variance: function variance(/*alpha, beta*/) {
   2183     throw new Error('variance not yet implemented');
   2184     // TODO: complete this
   2185   }
   2186 });
   2187 
   2188 
   2189 
   2190 // extend lognormal function with static methods
   2191 jStat.extend(jStat.lognormal, {
   2192   pdf: function pdf(x, mu, sigma) {
   2193     if (x <= 0)
   2194       return 0;
   2195     return Math.exp(-Math.log(x) - 0.5 * Math.log(2 * Math.PI) -
   2196                     Math.log(sigma) - Math.pow(Math.log(x) - mu, 2) /
   2197                     (2 * sigma * sigma));
   2198   },
   2199 
   2200   cdf: function cdf(x, mu, sigma) {
   2201     if (x < 0)
   2202       return 0;
   2203     return 0.5 +
   2204         (0.5 * jStat.erf((Math.log(x) - mu) / Math.sqrt(2 * sigma * sigma)));
   2205   },
   2206 
   2207   inv: function(p, mu, sigma) {
   2208     return Math.exp(-1.41421356237309505 * sigma * jStat.erfcinv(2 * p) + mu);
   2209   },
   2210 
   2211   mean: function mean(mu, sigma) {
   2212     return Math.exp(mu + sigma * sigma / 2);
   2213   },
   2214 
   2215   median: function median(mu/*, sigma*/) {
   2216     return Math.exp(mu);
   2217   },
   2218 
   2219   mode: function mode(mu, sigma) {
   2220     return Math.exp(mu - sigma * sigma);
   2221   },
   2222 
   2223   sample: function sample(mu, sigma) {
   2224     return Math.exp(jStat.randn() * sigma + mu);
   2225   },
   2226 
   2227   variance: function variance(mu, sigma) {
   2228     return (Math.exp(sigma * sigma) - 1) * Math.exp(2 * mu + sigma * sigma);
   2229   }
   2230 });
   2231 
   2232 
   2233 
   2234 // extend noncentralt function with static methods
   2235 jStat.extend(jStat.noncentralt, {
   2236   pdf: function pdf(x, dof, ncp) {
   2237     var tol = 1e-14;
   2238     if (Math.abs(ncp) < tol)  // ncp approx 0; use student-t
   2239       return jStat.studentt.pdf(x, dof)
   2240 
   2241     if (Math.abs(x) < tol) {  // different formula for x == 0
   2242       return Math.exp(jStat.gammaln((dof + 1) / 2) - ncp * ncp / 2 -
   2243                       0.5 * Math.log(Math.PI * dof) - jStat.gammaln(dof / 2));
   2244     }
   2245 
   2246     // formula for x != 0
   2247     return dof / x *
   2248         (jStat.noncentralt.cdf(x * Math.sqrt(1 + 2 / dof), dof+2, ncp) -
   2249          jStat.noncentralt.cdf(x, dof, ncp));
   2250   },
   2251 
   2252   cdf: function cdf(x, dof, ncp) {
   2253     var tol = 1e-14;
   2254     var min_iterations = 200;
   2255 
   2256     if (Math.abs(ncp) < tol)  // ncp approx 0; use student-t
   2257       return jStat.studentt.cdf(x, dof);
   2258 
   2259     // turn negative x into positive and flip result afterwards
   2260     var flip = false;
   2261     if (x < 0) {
   2262       flip = true;
   2263       ncp = -ncp;
   2264     }
   2265 
   2266     var prob = jStat.normal.cdf(-ncp, 0, 1);
   2267     var value = tol + 1;
   2268     // use value at last two steps to determine convergence
   2269     var lastvalue = value;
   2270     var y = x * x / (x * x + dof);
   2271     var j = 0;
   2272     var p = Math.exp(-ncp * ncp / 2);
   2273     var q = Math.exp(-ncp * ncp / 2 - 0.5 * Math.log(2) -
   2274                      jStat.gammaln(3 / 2)) * ncp;
   2275     while (j < min_iterations || lastvalue > tol || value > tol) {
   2276       lastvalue = value;
   2277       if (j > 0) {
   2278         p *= (ncp * ncp) / (2 * j);
   2279         q *= (ncp * ncp) / (2 * (j + 1 / 2));
   2280       }
   2281       value = p * jStat.beta.cdf(y, j + 0.5, dof / 2) +
   2282           q * jStat.beta.cdf(y, j+1, dof/2);
   2283       prob += 0.5 * value;
   2284       j++;
   2285     }
   2286 
   2287     return flip ? (1 - prob) : prob;
   2288   }
   2289 });
   2290 
   2291 
   2292 // extend normal function with static methods
   2293 jStat.extend(jStat.normal, {
   2294   pdf: function pdf(x, mean, std) {
   2295     return Math.exp(-0.5 * Math.log(2 * Math.PI) -
   2296                     Math.log(std) - Math.pow(x - mean, 2) / (2 * std * std));
   2297   },
   2298 
   2299   cdf: function cdf(x, mean, std) {
   2300     return 0.5 * (1 + jStat.erf((x - mean) / Math.sqrt(2 * std * std)));
   2301   },
   2302 
   2303   inv: function(p, mean, std) {
   2304     return -1.41421356237309505 * std * jStat.erfcinv(2 * p) + mean;
   2305   },
   2306 
   2307   mean : function(mean/*, std*/) {
   2308     return mean;
   2309   },
   2310 
   2311   median: function median(mean/*, std*/) {
   2312     return mean;
   2313   },
   2314 
   2315   mode: function (mean/*, std*/) {
   2316     return mean;
   2317   },
   2318 
   2319   sample: function sample(mean, std) {
   2320     return jStat.randn() * std + mean;
   2321   },
   2322 
   2323   variance : function(mean, std) {
   2324     return std * std;
   2325   }
   2326 });
   2327 
   2328 
   2329 
   2330 // extend pareto function with static methods
   2331 jStat.extend(jStat.pareto, {
   2332   pdf: function pdf(x, scale, shape) {
   2333     if (x < scale)
   2334       return 0;
   2335     return (shape * Math.pow(scale, shape)) / Math.pow(x, shape + 1);
   2336   },
   2337 
   2338   cdf: function cdf(x, scale, shape) {
   2339     if (x < scale)
   2340       return 0;
   2341     return 1 - Math.pow(scale / x, shape);
   2342   },
   2343 
   2344   inv: function inv(p, scale, shape) {
   2345     return scale / Math.pow(1 - p, 1 / shape);
   2346   },
   2347 
   2348   mean: function mean(scale, shape) {
   2349     if (shape <= 1)
   2350       return undefined;
   2351     return (shape * Math.pow(scale, shape)) / (shape - 1);
   2352   },
   2353 
   2354   median: function median(scale, shape) {
   2355     return scale * (shape * Math.SQRT2);
   2356   },
   2357 
   2358   mode: function mode(scale/*, shape*/) {
   2359     return scale;
   2360   },
   2361 
   2362   variance : function(scale, shape) {
   2363     if (shape <= 2)
   2364       return undefined;
   2365     return (scale*scale * shape) / (Math.pow(shape - 1, 2) * (shape - 2));
   2366   }
   2367 });
   2368 
   2369 
   2370 
   2371 // extend studentt function with static methods
   2372 jStat.extend(jStat.studentt, {
   2373   pdf: function pdf(x, dof) {
   2374     dof = dof > 1e100 ? 1e100 : dof;
   2375     return (1/(Math.sqrt(dof) * jStat.betafn(0.5, dof/2))) *
   2376         Math.pow(1 + ((x * x) / dof), -((dof + 1) / 2));
   2377   },
   2378 
   2379   cdf: function cdf(x, dof) {
   2380     var dof2 = dof / 2;
   2381     return jStat.ibeta((x + Math.sqrt(x * x + dof)) /
   2382                        (2 * Math.sqrt(x * x + dof)), dof2, dof2);
   2383   },
   2384 
   2385   inv: function(p, dof) {
   2386     var x = jStat.ibetainv(2 * Math.min(p, 1 - p), 0.5 * dof, 0.5);
   2387     x = Math.sqrt(dof * (1 - x) / x);
   2388     return (p > 0.5) ? x : -x;
   2389   },
   2390 
   2391   mean: function mean(dof) {
   2392     return (dof > 1) ? 0 : undefined;
   2393   },
   2394 
   2395   median: function median(/*dof*/) {
   2396     return 0;
   2397   },
   2398 
   2399   mode: function mode(/*dof*/) {
   2400     return 0;
   2401   },
   2402 
   2403   sample: function sample(dof) {
   2404     return jStat.randn() * Math.sqrt(dof / (2 * jStat.randg(dof / 2)));
   2405   },
   2406 
   2407   variance: function variance(dof) {
   2408     return (dof  > 2) ? dof / (dof - 2) : (dof > 1) ? Infinity : undefined;
   2409   }
   2410 });
   2411 
   2412 
   2413 
   2414 // extend weibull function with static methods
   2415 jStat.extend(jStat.weibull, {
   2416   pdf: function pdf(x, scale, shape) {
   2417     if (x < 0 || scale < 0 || shape < 0)
   2418       return 0;
   2419     return (shape / scale) * Math.pow((x / scale), (shape - 1)) *
   2420         Math.exp(-(Math.pow((x / scale), shape)));
   2421   },
   2422 
   2423   cdf: function cdf(x, scale, shape) {
   2424     return x < 0 ? 0 : 1 - Math.exp(-Math.pow((x / scale), shape));
   2425   },
   2426 
   2427   inv: function(p, scale, shape) {
   2428     return scale * Math.pow(-Math.log(1 - p), 1 / shape);
   2429   },
   2430 
   2431   mean : function(scale, shape) {
   2432     return scale * jStat.gammafn(1 + 1 / shape);
   2433   },
   2434 
   2435   median: function median(scale, shape) {
   2436     return scale * Math.pow(Math.log(2), 1 / shape);
   2437   },
   2438 
   2439   mode: function mode(scale, shape) {
   2440     if (shape <= 1)
   2441       return 0;
   2442     return scale * Math.pow((shape - 1) / shape, 1 / shape);
   2443   },
   2444 
   2445   sample: function sample(scale, shape) {
   2446     return scale * Math.pow(-Math.log(jStat._random_fn()), 1 / shape);
   2447   },
   2448 
   2449   variance: function variance(scale, shape) {
   2450     return scale * scale * jStat.gammafn(1 + 2 / shape) -
   2451         Math.pow(jStat.weibull.mean(scale, shape), 2);
   2452   }
   2453 });
   2454 
   2455 
   2456 
   2457 // extend uniform function with static methods
   2458 jStat.extend(jStat.uniform, {
   2459   pdf: function pdf(x, a, b) {
   2460     return (x < a || x > b) ? 0 : 1 / (b - a);
   2461   },
   2462 
   2463   cdf: function cdf(x, a, b) {
   2464     if (x < a)
   2465       return 0;
   2466     else if (x < b)
   2467       return (x - a) / (b - a);
   2468     return 1;
   2469   },
   2470 
   2471   inv: function(p, a, b) {
   2472     return a + (p * (b - a));
   2473   },
   2474 
   2475   mean: function mean(a, b) {
   2476     return 0.5 * (a + b);
   2477   },
   2478 
   2479   median: function median(a, b) {
   2480     return jStat.mean(a, b);
   2481   },
   2482 
   2483   mode: function mode(/*a, b*/) {
   2484     throw new Error('mode is not yet implemented');
   2485   },
   2486 
   2487   sample: function sample(a, b) {
   2488     return (a / 2 + b / 2) + (b / 2 - a / 2) * (2 * jStat._random_fn() - 1);
   2489   },
   2490 
   2491   variance: function variance(a, b) {
   2492     return Math.pow(b - a, 2) / 12;
   2493   }
   2494 });
   2495 
   2496 
   2497 // Got this from http://www.math.ucla.edu/~tom/distributions/binomial.html
   2498 function betinc(x, a, b, eps) {
   2499   var a0 = 0;
   2500   var b0 = 1;
   2501   var a1 = 1;
   2502   var b1 = 1;
   2503   var m9 = 0;
   2504   var a2 = 0;
   2505   var c9;
   2506 
   2507   while (Math.abs((a1 - a2) / a1) > eps) {
   2508     a2 = a1;
   2509     c9 = -(a + m9) * (a + b + m9) * x / (a + 2 * m9) / (a + 2 * m9 + 1);
   2510     a0 = a1 + c9 * a0;
   2511     b0 = b1 + c9 * b0;
   2512     m9 = m9 + 1;
   2513     c9 = m9 * (b - m9) * x / (a + 2 * m9 - 1) / (a + 2 * m9);
   2514     a1 = a0 + c9 * a1;
   2515     b1 = b0 + c9 * b1;
   2516     a0 = a0 / b1;
   2517     b0 = b0 / b1;
   2518     a1 = a1 / b1;
   2519     b1 = 1;
   2520   }
   2521 
   2522   return a1 / a;
   2523 }
   2524 
   2525 
   2526 // extend uniform function with static methods
   2527 jStat.extend(jStat.binomial, {
   2528   pdf: function pdf(k, n, p) {
   2529     return (p === 0 || p === 1) ?
   2530       ((n * p) === k ? 1 : 0) :
   2531       jStat.combination(n, k) * Math.pow(p, k) * Math.pow(1 - p, n - k);
   2532   },
   2533 
   2534   cdf: function cdf(x, n, p) {
   2535     var betacdf;
   2536     var eps = 1e-10;
   2537 
   2538     if (x < 0)
   2539       return 0;
   2540     if (x >= n)
   2541       return 1;
   2542     if (p < 0 || p > 1 || n <= 0)
   2543       return NaN;
   2544 
   2545     x = Math.floor(x);
   2546     var z = p;
   2547     var a = x + 1;
   2548     var b = n - x;
   2549     var s = a + b;
   2550     var bt = Math.exp(jStat.gammaln(s) - jStat.gammaln(b) -
   2551                       jStat.gammaln(a) + a * Math.log(z) + b * Math.log(1 - z));
   2552 
   2553     if (z < (a + 1) / (s + 2))
   2554       betacdf = bt * betinc(z, a, b, eps);
   2555     else
   2556       betacdf = 1 - bt * betinc(1 - z, b, a, eps);
   2557 
   2558     return Math.round((1 - betacdf) * (1 / eps)) / (1 / eps);
   2559   }
   2560 });
   2561 
   2562 
   2563 
   2564 // extend uniform function with static methods
   2565 jStat.extend(jStat.negbin, {
   2566   pdf: function pdf(k, r, p) {
   2567     if (k !== k >>> 0)
   2568       return false;
   2569     if (k < 0)
   2570       return 0;
   2571     return jStat.combination(k + r - 1, r - 1) *
   2572         Math.pow(1 - p, k) * Math.pow(p, r);
   2573   },
   2574 
   2575   cdf: function cdf(x, r, p) {
   2576     var sum = 0,
   2577     k = 0;
   2578     if (x < 0) return 0;
   2579     for (; k <= x; k++) {
   2580       sum += jStat.negbin.pdf(k, r, p);
   2581     }
   2582     return sum;
   2583   }
   2584 });
   2585 
   2586 
   2587 
   2588 // extend uniform function with static methods
   2589 jStat.extend(jStat.hypgeom, {
   2590   pdf: function pdf(k, N, m, n) {
   2591     // Hypergeometric PDF.
   2592 
   2593     // A simplification of the CDF algorithm below.
   2594 
   2595     // k = number of successes drawn
   2596     // N = population size
   2597     // m = number of successes in population
   2598     // n = number of items drawn from population
   2599 
   2600     if(k !== k | 0) {
   2601       return false;
   2602     } else if(k < 0 || k < m - (N - n)) {
   2603       // It's impossible to have this few successes drawn.
   2604       return 0;
   2605     } else if(k > n || k > m) {
   2606       // It's impossible to have this many successes drawn.
   2607       return 0;
   2608     } else if (m * 2 > N) {
   2609       // More than half the population is successes.
   2610 
   2611       if(n * 2 > N) {
   2612         // More than half the population is sampled.
   2613 
   2614         return jStat.hypgeom.pdf(N - m - n + k, N, N - m, N - n)
   2615       } else {
   2616         // Half or less of the population is sampled.
   2617 
   2618         return jStat.hypgeom.pdf(n - k, N, N - m, n);
   2619       }
   2620 
   2621     } else if(n * 2 > N) {
   2622       // Half or less is successes.
   2623 
   2624       return jStat.hypgeom.pdf(m - k, N, m, N - n);
   2625 
   2626     } else if(m < n) {
   2627       // We want to have the number of things sampled to be less than the
   2628       // successes available. So swap the definitions of successful and sampled.
   2629       return jStat.hypgeom.pdf(k, N, n, m);
   2630     } else {
   2631       // If we get here, half or less of the population was sampled, half or
   2632       // less of it was successes, and we had fewer sampled things than
   2633       // successes. Now we can do this complicated iterative algorithm in an
   2634       // efficient way.
   2635 
   2636       // The basic premise of the algorithm is that we partially normalize our
   2637       // intermediate product to keep it in a numerically good region, and then
   2638       // finish the normalization at the end.
   2639 
   2640       // This variable holds the scaled probability of the current number of
   2641       // successes.
   2642       var scaledPDF = 1;
   2643 
   2644       // This keeps track of how much we have normalized.
   2645       var samplesDone = 0;
   2646 
   2647       for(var i = 0; i < k; i++) {
   2648         // For every possible number of successes up to that observed...
   2649 
   2650         while(scaledPDF > 1 && samplesDone < n) {
   2651           // Intermediate result is growing too big. Apply some of the
   2652           // normalization to shrink everything.
   2653 
   2654           scaledPDF *= 1 - (m / (N - samplesDone));
   2655 
   2656           // Say we've normalized by this sample already.
   2657           samplesDone++;
   2658         }
   2659 
   2660         // Work out the partially-normalized hypergeometric PDF for the next
   2661         // number of successes
   2662         scaledPDF *= (n - i) * (m - i) / ((i + 1) * (N - m - n + i + 1));
   2663       }
   2664 
   2665       for(; samplesDone < n; samplesDone++) {
   2666         // Apply all the rest of the normalization
   2667         scaledPDF *= 1 - (m / (N - samplesDone));
   2668       }
   2669 
   2670       // Bound answer sanely before returning.
   2671       return Math.min(1, Math.max(0, scaledPDF));
   2672     }
   2673   },
   2674 
   2675   cdf: function cdf(x, N, m, n) {
   2676     // Hypergeometric CDF.
   2677 
   2678     // This algorithm is due to Prof. Thomas S. Ferguson, <tom@math.ucla.edu>,
   2679     // and comes from his hypergeometric test calculator at
   2680     // <http://www.math.ucla.edu/~tom/distributions/Hypergeometric.html>.
   2681 
   2682     // x = number of successes drawn
   2683     // N = population size
   2684     // m = number of successes in population
   2685     // n = number of items drawn from population
   2686 
   2687     if(x < 0 || x < m - (N - n)) {
   2688       // It's impossible to have this few successes drawn or fewer.
   2689       return 0;
   2690     } else if(x >= n || x >= m) {
   2691       // We will always have this many successes or fewer.
   2692       return 1;
   2693     } else if (m * 2 > N) {
   2694       // More than half the population is successes.
   2695 
   2696       if(n * 2 > N) {
   2697         // More than half the population is sampled.
   2698 
   2699         return jStat.hypgeom.cdf(N - m - n + x, N, N - m, N - n)
   2700       } else {
   2701         // Half or less of the population is sampled.
   2702 
   2703         return 1 - jStat.hypgeom.cdf(n - x - 1, N, N - m, n);
   2704       }
   2705 
   2706     } else if(n * 2 > N) {
   2707       // Half or less is successes.
   2708 
   2709       return 1 - jStat.hypgeom.cdf(m - x - 1, N, m, N - n);
   2710 
   2711     } else if(m < n) {
   2712       // We want to have the number of things sampled to be less than the
   2713       // successes available. So swap the definitions of successful and sampled.
   2714       return jStat.hypgeom.cdf(x, N, n, m);
   2715     } else {
   2716       // If we get here, half or less of the population was sampled, half or
   2717       // less of it was successes, and we had fewer sampled things than
   2718       // successes. Now we can do this complicated iterative algorithm in an
   2719       // efficient way.
   2720 
   2721       // The basic premise of the algorithm is that we partially normalize our
   2722       // intermediate sum to keep it in a numerically good region, and then
   2723       // finish the normalization at the end.
   2724 
   2725       // Holds the intermediate, scaled total CDF.
   2726       var scaledCDF = 1;
   2727 
   2728       // This variable holds the scaled probability of the current number of
   2729       // successes.
   2730       var scaledPDF = 1;
   2731 
   2732       // This keeps track of how much we have normalized.
   2733       var samplesDone = 0;
   2734 
   2735       for(var i = 0; i < x; i++) {
   2736         // For every possible number of successes up to that observed...
   2737 
   2738         while(scaledCDF > 1 && samplesDone < n) {
   2739           // Intermediate result is growing too big. Apply some of the
   2740           // normalization to shrink everything.
   2741 
   2742           var factor = 1 - (m / (N - samplesDone));
   2743 
   2744           scaledPDF *= factor;
   2745           scaledCDF *= factor;
   2746 
   2747           // Say we've normalized by this sample already.
   2748           samplesDone++;
   2749         }
   2750 
   2751         // Work out the partially-normalized hypergeometric PDF for the next
   2752         // number of successes
   2753         scaledPDF *= (n - i) * (m - i) / ((i + 1) * (N - m - n + i + 1));
   2754 
   2755         // Add to the CDF answer.
   2756         scaledCDF += scaledPDF;
   2757       }
   2758 
   2759       for(; samplesDone < n; samplesDone++) {
   2760         // Apply all the rest of the normalization
   2761         scaledCDF *= 1 - (m / (N - samplesDone));
   2762       }
   2763 
   2764       // Bound answer sanely before returning.
   2765       return Math.min(1, Math.max(0, scaledCDF));
   2766     }
   2767   }
   2768 });
   2769 
   2770 
   2771 
   2772 // extend uniform function with static methods
   2773 jStat.extend(jStat.poisson, {
   2774   pdf: function pdf(k, l) {
   2775     if (l < 0 || (k % 1) !== 0 || k < 0) {
   2776       return 0;
   2777     }
   2778 
   2779     return Math.pow(l, k) * Math.exp(-l) / jStat.factorial(k);
   2780   },
   2781 
   2782   cdf: function cdf(x, l) {
   2783     var sumarr = [],
   2784     k = 0;
   2785     if (x < 0) return 0;
   2786     for (; k <= x; k++) {
   2787       sumarr.push(jStat.poisson.pdf(k, l));
   2788     }
   2789     return jStat.sum(sumarr);
   2790   },
   2791 
   2792   mean : function(l) {
   2793     return l;
   2794   },
   2795 
   2796   variance : function(l) {
   2797     return l;
   2798   },
   2799 
   2800   sampleSmall: function sampleSmall(l) {
   2801     var p = 1, k = 0, L = Math.exp(-l);
   2802     do {
   2803       k++;
   2804       p *= jStat._random_fn();
   2805     } while (p > L);
   2806     return k - 1;
   2807   },
   2808 
   2809   sampleLarge: function sampleLarge(l) {
   2810     var lam = l;
   2811     var k;
   2812     var U, V, slam, loglam, a, b, invalpha, vr, us;
   2813 
   2814     slam = Math.sqrt(lam);
   2815     loglam = Math.log(lam);
   2816     b = 0.931 + 2.53 * slam;
   2817     a = -0.059 + 0.02483 * b;
   2818     invalpha = 1.1239 + 1.1328 / (b - 3.4);
   2819     vr = 0.9277 - 3.6224 / (b - 2);
   2820 
   2821     while (1) {
   2822       U = Math.random() - 0.5;
   2823       V = Math.random();
   2824       us = 0.5 - Math.abs(U);
   2825       k = Math.floor((2 * a / us + b) * U + lam + 0.43);
   2826       if ((us >= 0.07) && (V <= vr)) {
   2827           return k;
   2828       }
   2829       if ((k < 0) || ((us < 0.013) && (V > us))) {
   2830           continue;
   2831       }
   2832       /* log(V) == log(0.0) ok here */
   2833       /* if U==0.0 so that us==0.0, log is ok since always returns */
   2834       if ((Math.log(V) + Math.log(invalpha) - Math.log(a / (us * us) + b)) <= (-lam + k * loglam - jStat.loggam(k + 1))) {
   2835           return k;
   2836       }
   2837     }
   2838   },
   2839 
   2840   sample: function sample(l) {
   2841     if (l < 10)
   2842       return this.sampleSmall(l);
   2843     else
   2844       return this.sampleLarge(l);
   2845   }
   2846 });
   2847 
   2848 // extend triangular function with static methods
   2849 jStat.extend(jStat.triangular, {
   2850   pdf: function pdf(x, a, b, c) {
   2851     if (b <= a || c < a || c > b) {
   2852       return NaN;
   2853     } else {
   2854       if (x < a || x > b) {
   2855         return 0;
   2856       } else if (x < c) {
   2857           return (2 * (x - a)) / ((b - a) * (c - a));
   2858       } else if (x === c) {
   2859           return (2 / (b - a));
   2860       } else { // x > c
   2861           return (2 * (b - x)) / ((b - a) * (b - c));
   2862       }
   2863     }
   2864   },
   2865 
   2866   cdf: function cdf(x, a, b, c) {
   2867     if (b <= a || c < a || c > b)
   2868       return NaN;
   2869     if (x <= a)
   2870       return 0;
   2871     else if (x >= b)
   2872       return 1;
   2873     if (x <= c)
   2874       return Math.pow(x - a, 2) / ((b - a) * (c - a));
   2875     else // x > c
   2876       return 1 - Math.pow(b - x, 2) / ((b - a) * (b - c));
   2877   },
   2878 
   2879   inv: function inv(p, a, b, c) {
   2880     if (b <= a || c < a || c > b) {
   2881       return NaN;
   2882     } else {
   2883       if (p <= ((c - a) / (b - a))) {
   2884         return a + (b - a) * Math.sqrt(p * ((c - a) / (b - a)));
   2885       } else { // p > ((c - a) / (b - a))
   2886         return a + (b - a) * (1 - Math.sqrt((1 - p) * (1 - ((c - a) / (b - a)))));
   2887       }
   2888     }
   2889   },
   2890 
   2891   mean: function mean(a, b, c) {
   2892     return (a + b + c) / 3;
   2893   },
   2894 
   2895   median: function median(a, b, c) {
   2896     if (c <= (a + b) / 2) {
   2897       return b - Math.sqrt((b - a) * (b - c)) / Math.sqrt(2);
   2898     } else if (c > (a + b) / 2) {
   2899       return a + Math.sqrt((b - a) * (c - a)) / Math.sqrt(2);
   2900     }
   2901   },
   2902 
   2903   mode: function mode(a, b, c) {
   2904     return c;
   2905   },
   2906 
   2907   sample: function sample(a, b, c) {
   2908     var u = jStat._random_fn();
   2909     if (u < ((c - a) / (b - a)))
   2910       return a + Math.sqrt(u * (b - a) * (c - a))
   2911     return b - Math.sqrt((1 - u) * (b - a) * (b - c));
   2912   },
   2913 
   2914   variance: function variance(a, b, c) {
   2915     return (a * a + b * b + c * c - a * b - a * c - b * c) / 18;
   2916   }
   2917 });
   2918 
   2919 
   2920 // extend arcsine function with static methods
   2921 jStat.extend(jStat.arcsine, {
   2922   pdf: function pdf(x, a, b) {
   2923     if (b <= a) return NaN;
   2924 
   2925     return (x <= a || x >= b) ? 0 :
   2926       (2 / Math.PI) *
   2927         Math.pow(Math.pow(b - a, 2) -
   2928                   Math.pow(2 * x - a - b, 2), -0.5);
   2929   },
   2930 
   2931   cdf: function cdf(x, a, b) {
   2932     if (x < a)
   2933       return 0;
   2934     else if (x < b)
   2935       return (2 / Math.PI) * Math.asin(Math.sqrt((x - a)/(b - a)));
   2936     return 1;
   2937   },
   2938 
   2939   inv: function(p, a, b) {
   2940     return a + (0.5 - 0.5 * Math.cos(Math.PI * p)) * (b - a);
   2941   },
   2942 
   2943   mean: function mean(a, b) {
   2944     if (b <= a) return NaN;
   2945     return (a + b) / 2;
   2946   },
   2947 
   2948   median: function median(a, b) {
   2949     if (b <= a) return NaN;
   2950     return (a + b) / 2;
   2951   },
   2952 
   2953   mode: function mode(/*a, b*/) {
   2954     throw new Error('mode is not yet implemented');
   2955   },
   2956 
   2957   sample: function sample(a, b) {
   2958     return ((a + b) / 2) + ((b - a) / 2) *
   2959       Math.sin(2 * Math.PI * jStat.uniform.sample(0, 1));
   2960   },
   2961 
   2962   variance: function variance(a, b) {
   2963     if (b <= a) return NaN;
   2964     return Math.pow(b - a, 2) / 8;
   2965   }
   2966 });
   2967 
   2968 
   2969 function laplaceSign(x) { return x / Math.abs(x); }
   2970 
   2971 jStat.extend(jStat.laplace, {
   2972   pdf: function pdf(x, mu, b) {
   2973     return (b <= 0) ? 0 : (Math.exp(-Math.abs(x - mu) / b)) / (2 * b);
   2974   },
   2975 
   2976   cdf: function cdf(x, mu, b) {
   2977     if (b <= 0) { return 0; }
   2978 
   2979     if(x < mu) {
   2980       return 0.5 * Math.exp((x - mu) / b);
   2981     } else {
   2982       return 1 - 0.5 * Math.exp(- (x - mu) / b);
   2983     }
   2984   },
   2985 
   2986   mean: function(mu/*, b*/) {
   2987     return mu;
   2988   },
   2989 
   2990   median: function(mu/*, b*/) {
   2991     return mu;
   2992   },
   2993 
   2994   mode: function(mu/*, b*/) {
   2995     return mu;
   2996   },
   2997 
   2998   variance: function(mu, b) {
   2999     return 2 * b * b;
   3000   },
   3001 
   3002   sample: function sample(mu, b) {
   3003     var u = jStat._random_fn() - 0.5;
   3004 
   3005     return mu - (b * laplaceSign(u) * Math.log(1 - (2 * Math.abs(u))));
   3006   }
   3007 });
   3008 
   3009 function tukeyWprob(w, rr, cc) {
   3010   var nleg = 12;
   3011   var ihalf = 6;
   3012 
   3013   var C1 = -30;
   3014   var C2 = -50;
   3015   var C3 = 60;
   3016   var bb   = 8;
   3017   var wlar = 3;
   3018   var wincr1 = 2;
   3019   var wincr2 = 3;
   3020   var xleg = [
   3021     0.981560634246719250690549090149,
   3022     0.904117256370474856678465866119,
   3023     0.769902674194304687036893833213,
   3024     0.587317954286617447296702418941,
   3025     0.367831498998180193752691536644,
   3026     0.125233408511468915472441369464
   3027   ];
   3028   var aleg = [
   3029     0.047175336386511827194615961485,
   3030     0.106939325995318430960254718194,
   3031     0.160078328543346226334652529543,
   3032     0.203167426723065921749064455810,
   3033     0.233492536538354808760849898925,
   3034     0.249147045813402785000562436043
   3035   ];
   3036 
   3037   var qsqz = w * 0.5;
   3038 
   3039   // if w >= 16 then the integral lower bound (occurs for c=20)
   3040   // is 0.99999999999995 so return a value of 1.
   3041 
   3042   if (qsqz >= bb)
   3043     return 1.0;
   3044 
   3045   // find (f(w/2) - 1) ^ cc
   3046   // (first term in integral of hartley's form).
   3047 
   3048   var pr_w = 2 * jStat.normal.cdf(qsqz, 0, 1, 1, 0) - 1; // erf(qsqz / M_SQRT2)
   3049   // if pr_w ^ cc < 2e-22 then set pr_w = 0
   3050   if (pr_w >= Math.exp(C2 / cc))
   3051     pr_w = Math.pow(pr_w, cc);
   3052   else
   3053     pr_w = 0.0;
   3054 
   3055   // if w is large then the second component of the
   3056   // integral is small, so fewer intervals are needed.
   3057 
   3058   var wincr;
   3059   if (w > wlar)
   3060     wincr = wincr1;
   3061   else
   3062     wincr = wincr2;
   3063 
   3064   // find the integral of second term of hartley's form
   3065   // for the integral of the range for equal-length
   3066   // intervals using legendre quadrature.  limits of
   3067   // integration are from (w/2, 8).  two or three
   3068   // equal-length intervals are used.
   3069 
   3070   // blb and bub are lower and upper limits of integration.
   3071 
   3072   var blb = qsqz;
   3073   var binc = (bb - qsqz) / wincr;
   3074   var bub = blb + binc;
   3075   var einsum = 0.0;
   3076 
   3077   // integrate over each interval
   3078 
   3079   var cc1 = cc - 1.0;
   3080   for (var wi = 1; wi <= wincr; wi++) {
   3081     var elsum = 0.0;
   3082     var a = 0.5 * (bub + blb);
   3083 
   3084     // legendre quadrature with order = nleg
   3085 
   3086     var b = 0.5 * (bub - blb);
   3087 
   3088     for (var jj = 1; jj <= nleg; jj++) {
   3089       var j, xx;
   3090       if (ihalf < jj) {
   3091         j = (nleg - jj) + 1;
   3092         xx = xleg[j-1];
   3093       } else {
   3094         j = jj;
   3095         xx = -xleg[j-1];
   3096       }
   3097       var c = b * xx;
   3098       var ac = a + c;
   3099 
   3100       // if exp(-qexpo/2) < 9e-14,
   3101       // then doesn't contribute to integral
   3102 
   3103       var qexpo = ac * ac;
   3104       if (qexpo > C3)
   3105         break;
   3106 
   3107       var pplus = 2 * jStat.normal.cdf(ac, 0, 1, 1, 0);
   3108       var pminus= 2 * jStat.normal.cdf(ac, w, 1, 1, 0);
   3109 
   3110       // if rinsum ^ (cc-1) < 9e-14,
   3111       // then doesn't contribute to integral
   3112 
   3113       var rinsum = (pplus * 0.5) - (pminus * 0.5);
   3114       if (rinsum >= Math.exp(C1 / cc1)) {
   3115         rinsum = (aleg[j-1] * Math.exp(-(0.5 * qexpo))) * Math.pow(rinsum, cc1);
   3116         elsum += rinsum;
   3117       }
   3118     }
   3119     elsum *= (((2.0 * b) * cc) / Math.sqrt(2 * Math.PI));
   3120     einsum += elsum;
   3121     blb = bub;
   3122     bub += binc;
   3123   }
   3124 
   3125   // if pr_w ^ rr < 9e-14, then return 0
   3126   pr_w += einsum;
   3127   if (pr_w <= Math.exp(C1 / rr))
   3128     return 0;
   3129 
   3130   pr_w = Math.pow(pr_w, rr);
   3131   if (pr_w >= 1) // 1 was iMax was eps
   3132     return 1;
   3133   return pr_w;
   3134 }
   3135 
   3136 function tukeyQinv(p, c, v) {
   3137   var p0 = 0.322232421088;
   3138   var q0 = 0.993484626060e-01;
   3139   var p1 = -1.0;
   3140   var q1 = 0.588581570495;
   3141   var p2 = -0.342242088547;
   3142   var q2 = 0.531103462366;
   3143   var p3 = -0.204231210125;
   3144   var q3 = 0.103537752850;
   3145   var p4 = -0.453642210148e-04;
   3146   var q4 = 0.38560700634e-02;
   3147   var c1 = 0.8832;
   3148   var c2 = 0.2368;
   3149   var c3 = 1.214;
   3150   var c4 = 1.208;
   3151   var c5 = 1.4142;
   3152   var vmax = 120.0;
   3153 
   3154   var ps = 0.5 - 0.5 * p;
   3155   var yi = Math.sqrt(Math.log(1.0 / (ps * ps)));
   3156   var t = yi + (((( yi * p4 + p3) * yi + p2) * yi + p1) * yi + p0)
   3157      / (((( yi * q4 + q3) * yi + q2) * yi + q1) * yi + q0);
   3158   if (v < vmax) t += (t * t * t + t) / v / 4.0;
   3159   var q = c1 - c2 * t;
   3160   if (v < vmax) q += -c3 / v + c4 * t / v;
   3161   return t * (q * Math.log(c - 1.0) + c5);
   3162 }
   3163 
   3164 jStat.extend(jStat.tukey, {
   3165   cdf: function cdf(q, nmeans, df) {
   3166     // Identical implementation as the R ptukey() function as of commit 68947
   3167     var rr = 1;
   3168     var cc = nmeans;
   3169 
   3170     var nlegq = 16;
   3171     var ihalfq = 8;
   3172 
   3173     var eps1 = -30.0;
   3174     var eps2 = 1.0e-14;
   3175     var dhaf  = 100.0;
   3176     var dquar = 800.0;
   3177     var deigh = 5000.0;
   3178     var dlarg = 25000.0;
   3179     var ulen1 = 1.0;
   3180     var ulen2 = 0.5;
   3181     var ulen3 = 0.25;
   3182     var ulen4 = 0.125;
   3183     var xlegq = [
   3184       0.989400934991649932596154173450,
   3185       0.944575023073232576077988415535,
   3186       0.865631202387831743880467897712,
   3187       0.755404408355003033895101194847,
   3188       0.617876244402643748446671764049,
   3189       0.458016777657227386342419442984,
   3190       0.281603550779258913230460501460,
   3191       0.950125098376374401853193354250e-1
   3192     ];
   3193     var alegq = [
   3194       0.271524594117540948517805724560e-1,
   3195       0.622535239386478928628438369944e-1,
   3196       0.951585116824927848099251076022e-1,
   3197       0.124628971255533872052476282192,
   3198       0.149595988816576732081501730547,
   3199       0.169156519395002538189312079030,
   3200       0.182603415044923588866763667969,
   3201       0.189450610455068496285396723208
   3202     ];
   3203 
   3204     if (q <= 0)
   3205       return 0;
   3206 
   3207     // df must be > 1
   3208     // there must be at least two values
   3209 
   3210     if (df < 2 || rr < 1 || cc < 2) return NaN;
   3211 
   3212     if (!Number.isFinite(q))
   3213       return 1;
   3214 
   3215     if (df > dlarg)
   3216       return tukeyWprob(q, rr, cc);
   3217 
   3218     // calculate leading constant
   3219 
   3220     var f2 = df * 0.5;
   3221     var f2lf = ((f2 * Math.log(df)) - (df * Math.log(2))) - jStat.gammaln(f2);
   3222     var f21 = f2 - 1.0;
   3223 
   3224     // integral is divided into unit, half-unit, quarter-unit, or
   3225     // eighth-unit length intervals depending on the value of the
   3226     // degrees of freedom.
   3227 
   3228     var ff4 = df * 0.25;
   3229     var ulen;
   3230     if      (df <= dhaf)  ulen = ulen1;
   3231     else if (df <= dquar) ulen = ulen2;
   3232     else if (df <= deigh) ulen = ulen3;
   3233     else                  ulen = ulen4;
   3234 
   3235     f2lf += Math.log(ulen);
   3236 
   3237     // integrate over each subinterval
   3238 
   3239     var ans = 0.0;
   3240 
   3241     for (var i = 1; i <= 50; i++) {
   3242       var otsum = 0.0;
   3243 
   3244       // legendre quadrature with order = nlegq
   3245       // nodes (stored in xlegq) are symmetric around zero.
   3246 
   3247       var twa1 = (2 * i - 1) * ulen;
   3248 
   3249       for (var jj = 1; jj <= nlegq; jj++) {
   3250         var j, t1;
   3251         if (ihalfq < jj) {
   3252           j = jj - ihalfq - 1;
   3253           t1 = (f2lf + (f21 * Math.log(twa1 + (xlegq[j] * ulen))))
   3254               - (((xlegq[j] * ulen) + twa1) * ff4);
   3255         } else {
   3256           j = jj - 1;
   3257           t1 = (f2lf + (f21 * Math.log(twa1 - (xlegq[j] * ulen))))
   3258               + (((xlegq[j] * ulen) - twa1) * ff4);
   3259         }
   3260 
   3261         // if exp(t1) < 9e-14, then doesn't contribute to integral
   3262         var qsqz;
   3263         if (t1 >= eps1) {
   3264           if (ihalfq < jj) {
   3265             qsqz = q * Math.sqrt(((xlegq[j] * ulen) + twa1) * 0.5);
   3266           } else {
   3267             qsqz = q * Math.sqrt(((-(xlegq[j] * ulen)) + twa1) * 0.5);
   3268           }
   3269 
   3270           // call wprob to find integral of range portion
   3271 
   3272           var wprb = tukeyWprob(qsqz, rr, cc);
   3273           var rotsum = (wprb * alegq[j]) * Math.exp(t1);
   3274           otsum += rotsum;
   3275         }
   3276         // end legendre integral for interval i
   3277         // L200:
   3278       }
   3279 
   3280       // if integral for interval i < 1e-14, then stop.
   3281       // However, in order to avoid small area under left tail,
   3282       // at least  1 / ulen  intervals are calculated.
   3283       if (i * ulen >= 1.0 && otsum <= eps2)
   3284         break;
   3285 
   3286       // end of interval i
   3287       // L330:
   3288 
   3289       ans += otsum;
   3290     }
   3291 
   3292     if (otsum > eps2) { // not converged
   3293       throw new Error('tukey.cdf failed to converge');
   3294     }
   3295     if (ans > 1)
   3296       ans = 1;
   3297     return ans;
   3298   },
   3299 
   3300   inv: function(p, nmeans, df) {
   3301     // Identical implementation as the R qtukey() function as of commit 68947
   3302     var rr = 1;
   3303     var cc = nmeans;
   3304 
   3305     var eps = 0.0001;
   3306     var maxiter = 50;
   3307 
   3308     // df must be > 1 ; there must be at least two values
   3309     if (df < 2 || rr < 1 || cc < 2) return NaN;
   3310 
   3311     if (p < 0 || p > 1) return NaN;
   3312     if (p === 0) return 0;
   3313     if (p === 1) return Infinity;
   3314 
   3315     // Initial value
   3316 
   3317     var x0 = tukeyQinv(p, cc, df);
   3318 
   3319     // Find prob(value < x0)
   3320 
   3321     var valx0 = jStat.tukey.cdf(x0, nmeans, df) - p;
   3322 
   3323     // Find the second iterate and prob(value < x1).
   3324     // If the first iterate has probability value
   3325     // exceeding p then second iterate is 1 less than
   3326     // first iterate; otherwise it is 1 greater.
   3327 
   3328     var x1;
   3329     if (valx0 > 0.0)
   3330       x1 = Math.max(0.0, x0 - 1.0);
   3331     else
   3332       x1 = x0 + 1.0;
   3333     var valx1 = jStat.tukey.cdf(x1, nmeans, df) - p;
   3334 
   3335     // Find new iterate
   3336 
   3337     var ans;
   3338     for(var iter = 1; iter < maxiter; iter++) {
   3339       ans = x1 - ((valx1 * (x1 - x0)) / (valx1 - valx0));
   3340       valx0 = valx1;
   3341 
   3342       // New iterate must be >= 0
   3343 
   3344       x0 = x1;
   3345       if (ans < 0.0) {
   3346         ans = 0.0;
   3347         valx1 = -p;
   3348       }
   3349       // Find prob(value < new iterate)
   3350 
   3351       valx1 = jStat.tukey.cdf(ans, nmeans, df) - p;
   3352       x1 = ans;
   3353 
   3354       // If the difference between two successive
   3355       // iterates is less than eps, stop
   3356 
   3357       var xabs = Math.abs(x1 - x0);
   3358       if (xabs < eps)
   3359         return ans;
   3360     }
   3361 
   3362     throw new Error('tukey.inv failed to converge');
   3363   }
   3364 });
   3365 
   3366 }(jStat, Math));
   3367 /* Provides functions for the solution of linear system of equations, integration, extrapolation,
   3368  * interpolation, eigenvalue problems, differential equations and PCA analysis. */
   3369 
   3370 (function(jStat, Math) {
   3371 
   3372 var push = Array.prototype.push;
   3373 var isArray = jStat.utils.isArray;
   3374 
   3375 function isUsable(arg) {
   3376   return isArray(arg) || arg instanceof jStat;
   3377 }
   3378 
   3379 jStat.extend({
   3380 
   3381   // add a vector/matrix to a vector/matrix or scalar
   3382   add: function add(arr, arg) {
   3383     // check if arg is a vector or scalar
   3384     if (isUsable(arg)) {
   3385       if (!isUsable(arg[0])) arg = [ arg ];
   3386       return jStat.map(arr, function(value, row, col) {
   3387         return value + arg[row][col];
   3388       });
   3389     }
   3390     return jStat.map(arr, function(value) { return value + arg; });
   3391   },
   3392 
   3393   // subtract a vector or scalar from the vector
   3394   subtract: function subtract(arr, arg) {
   3395     // check if arg is a vector or scalar
   3396     if (isUsable(arg)) {
   3397       if (!isUsable(arg[0])) arg = [ arg ];
   3398       return jStat.map(arr, function(value, row, col) {
   3399         return value - arg[row][col] || 0;
   3400       });
   3401     }
   3402     return jStat.map(arr, function(value) { return value - arg; });
   3403   },
   3404 
   3405   // matrix division
   3406   divide: function divide(arr, arg) {
   3407     if (isUsable(arg)) {
   3408       if (!isUsable(arg[0])) arg = [ arg ];
   3409       return jStat.multiply(arr, jStat.inv(arg));
   3410     }
   3411     return jStat.map(arr, function(value) { return value / arg; });
   3412   },
   3413 
   3414   // matrix multiplication
   3415   multiply: function multiply(arr, arg) {
   3416     var row, col, nrescols, sum, nrow, ncol, res, rescols;
   3417     // eg: arr = 2 arg = 3 -> 6 for res[0][0] statement closure
   3418     if (arr.length === undefined && arg.length === undefined) {
   3419       return arr * arg;
   3420     }
   3421     nrow = arr.length,
   3422     ncol = arr[0].length,
   3423     res = jStat.zeros(nrow, nrescols = (isUsable(arg)) ? arg[0].length : ncol),
   3424     rescols = 0;
   3425     if (isUsable(arg)) {
   3426       for (; rescols < nrescols; rescols++) {
   3427         for (row = 0; row < nrow; row++) {
   3428           sum = 0;
   3429           for (col = 0; col < ncol; col++)
   3430           sum += arr[row][col] * arg[col][rescols];
   3431           res[row][rescols] = sum;
   3432         }
   3433       }
   3434       return (nrow === 1 && rescols === 1) ? res[0][0] : res;
   3435     }
   3436     return jStat.map(arr, function(value) { return value * arg; });
   3437   },
   3438 
   3439   // outer([1,2,3],[4,5,6])
   3440   // ===
   3441   // [[1],[2],[3]] times [[4,5,6]]
   3442   // ->
   3443   // [[4,5,6],[8,10,12],[12,15,18]]
   3444   outer:function outer(A, B) {
   3445     return jStat.multiply(A.map(function(t){ return [t] }), [B]);
   3446   },
   3447 
   3448 
   3449   // Returns the dot product of two matricies
   3450   dot: function dot(arr, arg) {
   3451     if (!isUsable(arr[0])) arr = [ arr ];
   3452     if (!isUsable(arg[0])) arg = [ arg ];
   3453     // convert column to row vector
   3454     var left = (arr[0].length === 1 && arr.length !== 1) ? jStat.transpose(arr) : arr,
   3455     right = (arg[0].length === 1 && arg.length !== 1) ? jStat.transpose(arg) : arg,
   3456     res = [],
   3457     row = 0,
   3458     nrow = left.length,
   3459     ncol = left[0].length,
   3460     sum, col;
   3461     for (; row < nrow; row++) {
   3462       res[row] = [];
   3463       sum = 0;
   3464       for (col = 0; col < ncol; col++)
   3465       sum += left[row][col] * right[row][col];
   3466       res[row] = sum;
   3467     }
   3468     return (res.length === 1) ? res[0] : res;
   3469   },
   3470 
   3471   // raise every element by a scalar
   3472   pow: function pow(arr, arg) {
   3473     return jStat.map(arr, function(value) { return Math.pow(value, arg); });
   3474   },
   3475 
   3476   // exponentiate every element
   3477   exp: function exp(arr) {
   3478     return jStat.map(arr, function(value) { return Math.exp(value); });
   3479   },
   3480 
   3481   // generate the natural log of every element
   3482   log: function exp(arr) {
   3483     return jStat.map(arr, function(value) { return Math.log(value); });
   3484   },
   3485 
   3486   // generate the absolute values of the vector
   3487   abs: function abs(arr) {
   3488     return jStat.map(arr, function(value) { return Math.abs(value); });
   3489   },
   3490 
   3491   // computes the p-norm of the vector
   3492   // In the case that a matrix is passed, uses the first row as the vector
   3493   norm: function norm(arr, p) {
   3494     var nnorm = 0,
   3495     i = 0;
   3496     // check the p-value of the norm, and set for most common case
   3497     if (isNaN(p)) p = 2;
   3498     // check if multi-dimensional array, and make vector correction
   3499     if (isUsable(arr[0])) arr = arr[0];
   3500     // vector norm
   3501     for (; i < arr.length; i++) {
   3502       nnorm += Math.pow(Math.abs(arr[i]), p);
   3503     }
   3504     return Math.pow(nnorm, 1 / p);
   3505   },
   3506 
   3507   // computes the angle between two vectors in rads
   3508   // In case a matrix is passed, this uses the first row as the vector
   3509   angle: function angle(arr, arg) {
   3510     return Math.acos(jStat.dot(arr, arg) / (jStat.norm(arr) * jStat.norm(arg)));
   3511   },
   3512 
   3513   // augment one matrix by another
   3514   // Note: this function returns a matrix, not a jStat object
   3515   aug: function aug(a, b) {
   3516     var newarr = [];
   3517     var i;
   3518     for (i = 0; i < a.length; i++) {
   3519       newarr.push(a[i].slice());
   3520     }
   3521     for (i = 0; i < newarr.length; i++) {
   3522       push.apply(newarr[i], b[i]);
   3523     }
   3524     return newarr;
   3525   },
   3526 
   3527   // The inv() function calculates the inverse of a matrix
   3528   // Create the inverse by augmenting the matrix by the identity matrix of the
   3529   // appropriate size, and then use G-J elimination on the augmented matrix.
   3530   inv: function inv(a) {
   3531     var rows = a.length;
   3532     var cols = a[0].length;
   3533     var b = jStat.identity(rows, cols);
   3534     var c = jStat.gauss_jordan(a, b);
   3535     var result = [];
   3536     var i = 0;
   3537     var j;
   3538 
   3539     //We need to copy the inverse portion to a new matrix to rid G-J artifacts
   3540     for (; i < rows; i++) {
   3541       result[i] = [];
   3542       for (j = cols; j < c[0].length; j++)
   3543         result[i][j - cols] = c[i][j];
   3544     }
   3545     return result;
   3546   },
   3547 
   3548   // calculate the determinant of a matrix
   3549   det: function det(a) {
   3550     if (a.length === 2) {
   3551       return a[0][0] * a[1][1] - a[0][1] * a[1][0];
   3552     }
   3553 
   3554     var determinant = 0;
   3555     for (var i = 0; i < a.length; i++) {
   3556       // build a sub matrix without column `i`
   3557       var submatrix = [];
   3558       for (var row = 1; row < a.length; row++) {
   3559         submatrix[row - 1] = [];
   3560         for (var col = 0; col < a.length; col++) {
   3561           if (col < i) {
   3562             submatrix[row - 1][col] = a[row][col];
   3563           } else if (col > i) {
   3564             submatrix[row - 1][col - 1] = a[row][col];
   3565           }
   3566         }
   3567       }
   3568 
   3569       // alternate between + and - between determinants
   3570       var sign = i % 2 ? -1 : 1;
   3571       determinant += det(submatrix) * a[0][i] * sign;
   3572     }
   3573 
   3574     return determinant
   3575   },
   3576 
   3577   gauss_elimination: function gauss_elimination(a, b) {
   3578     var i = 0,
   3579     j = 0,
   3580     n = a.length,
   3581     m = a[0].length,
   3582     factor = 1,
   3583     sum = 0,
   3584     x = [],
   3585     maug, pivot, temp, k;
   3586     a = jStat.aug(a, b);
   3587     maug = a[0].length;
   3588     for(i = 0; i < n; i++) {
   3589       pivot = a[i][i];
   3590       j = i;
   3591       for (k = i + 1; k < m; k++) {
   3592         if (pivot < Math.abs(a[k][i])) {
   3593           pivot = a[k][i];
   3594           j = k;
   3595         }
   3596       }
   3597       if (j != i) {
   3598         for(k = 0; k < maug; k++) {
   3599           temp = a[i][k];
   3600           a[i][k] = a[j][k];
   3601           a[j][k] = temp;
   3602         }
   3603       }
   3604       for (j = i + 1; j < n; j++) {
   3605         factor = a[j][i] / a[i][i];
   3606         for(k = i; k < maug; k++) {
   3607           a[j][k] = a[j][k] - factor * a[i][k];
   3608         }
   3609       }
   3610     }
   3611     for (i = n - 1; i >= 0; i--) {
   3612       sum = 0;
   3613       for (j = i + 1; j<= n - 1; j++) {
   3614         sum = sum + x[j] * a[i][j];
   3615       }
   3616       x[i] =(a[i][maug - 1] - sum) / a[i][i];
   3617     }
   3618     return x;
   3619   },
   3620 
   3621   gauss_jordan: function gauss_jordan(a, b) {
   3622     var m = jStat.aug(a, b);
   3623     var h = m.length;
   3624     var w = m[0].length;
   3625     var c = 0;
   3626     var x, y, y2;
   3627     // find max pivot
   3628     for (y = 0; y < h; y++) {
   3629       var maxrow = y;
   3630       for (y2 = y+1; y2 < h; y2++) {
   3631         if (Math.abs(m[y2][y]) > Math.abs(m[maxrow][y]))
   3632           maxrow = y2;
   3633       }
   3634       var tmp = m[y];
   3635       m[y] = m[maxrow];
   3636       m[maxrow] = tmp
   3637       for (y2 = y+1; y2 < h; y2++) {
   3638         c = m[y2][y] / m[y][y];
   3639         for (x = y; x < w; x++) {
   3640           m[y2][x] -= m[y][x] * c;
   3641         }
   3642       }
   3643     }
   3644     // backsubstitute
   3645     for (y = h-1; y >= 0; y--) {
   3646       c = m[y][y];
   3647       for (y2 = 0; y2 < y; y2++) {
   3648         for (x = w-1; x > y-1; x--) {
   3649           m[y2][x] -= m[y][x] * m[y2][y] / c;
   3650         }
   3651       }
   3652       m[y][y] /= c;
   3653       for (x = h; x < w; x++) {
   3654         m[y][x] /= c;
   3655       }
   3656     }
   3657     return m;
   3658   },
   3659 
   3660   // solve equation
   3661   // Ax=b
   3662   // A is upper triangular matrix
   3663   // A=[[1,2,3],[0,4,5],[0,6,7]]
   3664   // b=[1,2,3]
   3665   // triaUpSolve(A,b) // -> [2.666,0.1666,1.666]
   3666   // if you use matrix style
   3667   // A=[[1,2,3],[0,4,5],[0,6,7]]
   3668   // b=[[1],[2],[3]]
   3669   // will return [[2.666],[0.1666],[1.666]]
   3670   triaUpSolve: function triaUpSolve(A, b) {
   3671     var size = A[0].length;
   3672     var x = jStat.zeros(1, size)[0];
   3673     var parts;
   3674     var matrix_mode = false;
   3675 
   3676     if (b[0].length != undefined) {
   3677       b = b.map(function(i){ return i[0] });
   3678       matrix_mode = true;
   3679     }
   3680 
   3681     jStat.arange(size - 1, -1, -1).forEach(function(i) {
   3682       parts = jStat.arange(i + 1, size).map(function(j) {
   3683         return x[j] * A[i][j];
   3684       });
   3685       x[i] = (b[i] - jStat.sum(parts)) / A[i][i];
   3686     });
   3687 
   3688     if (matrix_mode)
   3689       return x.map(function(i){ return [i] });
   3690     return x;
   3691   },
   3692 
   3693   triaLowSolve: function triaLowSolve(A, b) {
   3694     // like to triaUpSolve but A is lower triangular matrix
   3695     var size = A[0].length;
   3696     var x = jStat.zeros(1, size)[0];
   3697     var parts;
   3698 
   3699     var matrix_mode=false;
   3700     if (b[0].length != undefined) {
   3701       b = b.map(function(i){ return i[0] });
   3702       matrix_mode = true;
   3703     }
   3704 
   3705     jStat.arange(size).forEach(function(i) {
   3706       parts = jStat.arange(i).map(function(j) {
   3707         return A[i][j] * x[j];
   3708       });
   3709       x[i] = (b[i] - jStat.sum(parts)) / A[i][i];
   3710     })
   3711 
   3712     if (matrix_mode)
   3713       return x.map(function(i){ return [i] });
   3714     return x;
   3715   },
   3716 
   3717 
   3718   // A -> [L,U]
   3719   // A=LU
   3720   // L is lower triangular matrix
   3721   // U is upper triangular matrix
   3722   lu: function lu(A) {
   3723     var size = A.length;
   3724     //var L=jStat.diagonal(jStat.ones(1,size)[0]);
   3725     var L = jStat.identity(size);
   3726     var R = jStat.zeros(A.length, A[0].length);
   3727     var parts;
   3728     jStat.arange(size).forEach(function(t) {
   3729       R[0][t] = A[0][t];
   3730     });
   3731     jStat.arange(1, size).forEach(function(l) {
   3732       jStat.arange(l).forEach(function(i) {
   3733         parts = jStat.arange(i).map(function(jj) {
   3734           return L[l][jj] * R[jj][i];
   3735         });
   3736         L[l][i] = (A[l][i] - jStat.sum(parts)) / R[i][i];
   3737       });
   3738       jStat.arange(l, size).forEach(function(j) {
   3739         parts = jStat.arange(l).map(function(jj) {
   3740           return L[l][jj] * R[jj][j];
   3741         });
   3742         R[l][j] = A[parts.length][j] - jStat.sum(parts);
   3743       });
   3744     });
   3745     return [L, R];
   3746   },
   3747 
   3748   // A -> T
   3749   // A=TT'
   3750   // T is lower triangular matrix
   3751   cholesky: function cholesky(A) {
   3752     var size = A.length;
   3753     var T = jStat.zeros(A.length, A[0].length);
   3754     var parts;
   3755     jStat.arange(size).forEach(function(i) {
   3756       parts = jStat.arange(i).map(function(t) {
   3757         return Math.pow(T[i][t],2);
   3758       });
   3759       T[i][i] = Math.sqrt(A[i][i] - jStat.sum(parts));
   3760       jStat.arange(i + 1, size).forEach(function(j) {
   3761         parts = jStat.arange(i).map(function(t) {
   3762           return T[i][t] * T[j][t];
   3763         });
   3764         T[j][i] = (A[i][j] - jStat.sum(parts)) / T[i][i];
   3765       });
   3766     });
   3767     return T;
   3768   },
   3769 
   3770 
   3771   gauss_jacobi: function gauss_jacobi(a, b, x, r) {
   3772     var i = 0;
   3773     var j = 0;
   3774     var n = a.length;
   3775     var l = [];
   3776     var u = [];
   3777     var d = [];
   3778     var xv, c, h, xk;
   3779     for (; i < n; i++) {
   3780       l[i] = [];
   3781       u[i] = [];
   3782       d[i] = [];
   3783       for (j = 0; j < n; j++) {
   3784         if (i > j) {
   3785           l[i][j] = a[i][j];
   3786           u[i][j] = d[i][j] = 0;
   3787         } else if (i < j) {
   3788           u[i][j] = a[i][j];
   3789           l[i][j] = d[i][j] = 0;
   3790         } else {
   3791           d[i][j] = a[i][j];
   3792           l[i][j] = u[i][j] = 0;
   3793         }
   3794       }
   3795     }
   3796     h = jStat.multiply(jStat.multiply(jStat.inv(d), jStat.add(l, u)), -1);
   3797     c = jStat.multiply(jStat.inv(d), b);
   3798     xv = x;
   3799     xk = jStat.add(jStat.multiply(h, x), c);
   3800     i = 2;
   3801     while (Math.abs(jStat.norm(jStat.subtract(xk,xv))) > r) {
   3802       xv = xk;
   3803       xk = jStat.add(jStat.multiply(h, xv), c);
   3804       i++;
   3805     }
   3806     return xk;
   3807   },
   3808 
   3809   gauss_seidel: function gauss_seidel(a, b, x, r) {
   3810     var i = 0;
   3811     var n = a.length;
   3812     var l = [];
   3813     var u = [];
   3814     var d = [];
   3815     var j, xv, c, h, xk;
   3816     for (; i < n; i++) {
   3817       l[i] = [];
   3818       u[i] = [];
   3819       d[i] = [];
   3820       for (j = 0; j < n; j++) {
   3821         if (i > j) {
   3822           l[i][j] = a[i][j];
   3823           u[i][j] = d[i][j] = 0;
   3824         } else if (i < j) {
   3825           u[i][j] = a[i][j];
   3826           l[i][j] = d[i][j] = 0;
   3827         } else {
   3828           d[i][j] = a[i][j];
   3829           l[i][j] = u[i][j] = 0;
   3830         }
   3831       }
   3832     }
   3833     h = jStat.multiply(jStat.multiply(jStat.inv(jStat.add(d, l)), u), -1);
   3834     c = jStat.multiply(jStat.inv(jStat.add(d, l)), b);
   3835     xv = x;
   3836     xk = jStat.add(jStat.multiply(h, x), c);
   3837     i = 2;
   3838     while (Math.abs(jStat.norm(jStat.subtract(xk, xv))) > r) {
   3839       xv = xk;
   3840       xk = jStat.add(jStat.multiply(h, xv), c);
   3841       i = i + 1;
   3842     }
   3843     return xk;
   3844   },
   3845 
   3846   SOR: function SOR(a, b, x, r, w) {
   3847     var i = 0;
   3848     var n = a.length;
   3849     var l = [];
   3850     var u = [];
   3851     var d = [];
   3852     var j, xv, c, h, xk;
   3853     for (; i < n; i++) {
   3854       l[i] = [];
   3855       u[i] = [];
   3856       d[i] = [];
   3857       for (j = 0; j < n; j++) {
   3858         if (i > j) {
   3859           l[i][j] = a[i][j];
   3860           u[i][j] = d[i][j] = 0;
   3861         } else if (i < j) {
   3862           u[i][j] = a[i][j];
   3863           l[i][j] = d[i][j] = 0;
   3864         } else {
   3865           d[i][j] = a[i][j];
   3866           l[i][j] = u[i][j] = 0;
   3867         }
   3868       }
   3869     }
   3870     h = jStat.multiply(jStat.inv(jStat.add(d, jStat.multiply(l, w))),
   3871                        jStat.subtract(jStat.multiply(d, 1 - w),
   3872                                       jStat.multiply(u, w)));
   3873     c = jStat.multiply(jStat.multiply(jStat.inv(jStat.add(d,
   3874         jStat.multiply(l, w))), b), w);
   3875     xv = x;
   3876     xk = jStat.add(jStat.multiply(h, x), c);
   3877     i = 2;
   3878     while (Math.abs(jStat.norm(jStat.subtract(xk, xv))) > r) {
   3879       xv = xk;
   3880       xk = jStat.add(jStat.multiply(h, xv), c);
   3881       i++;
   3882     }
   3883     return xk;
   3884   },
   3885 
   3886   householder: function householder(a) {
   3887     var m = a.length;
   3888     var n = a[0].length;
   3889     var i = 0;
   3890     var w = [];
   3891     var p = [];
   3892     var alpha, r, k, j, factor;
   3893     for (; i < m - 1; i++) {
   3894       alpha = 0;
   3895       for (j = i + 1; j < n; j++)
   3896       alpha += (a[j][i] * a[j][i]);
   3897       factor = (a[i + 1][i] > 0) ? -1 : 1;
   3898       alpha = factor * Math.sqrt(alpha);
   3899       r = Math.sqrt((((alpha * alpha) - a[i + 1][i] * alpha) / 2));
   3900       w = jStat.zeros(m, 1);
   3901       w[i + 1][0] = (a[i + 1][i] - alpha) / (2 * r);
   3902       for (k = i + 2; k < m; k++) w[k][0] = a[k][i] / (2 * r);
   3903       p = jStat.subtract(jStat.identity(m, n),
   3904           jStat.multiply(jStat.multiply(w, jStat.transpose(w)), 2));
   3905       a = jStat.multiply(p, jStat.multiply(a, p));
   3906     }
   3907     return a;
   3908   },
   3909 
   3910   // A -> [Q,R]
   3911   // Q is orthogonal matrix
   3912   // R is upper triangular
   3913   QR: (function() {
   3914     // x -> Q
   3915     // find a orthogonal matrix Q st.
   3916     // Qx=y
   3917     // y is [||x||,0,0,...]
   3918 
   3919     // quick ref
   3920     var sum   = jStat.sum;
   3921     var range = jStat.arange;
   3922 
   3923     function qr2(x) {
   3924       // quick impletation
   3925       // https://www.stat.wisc.edu/~larget/math496/qr.html
   3926 
   3927       var n = x.length;
   3928       var p = x[0].length;
   3929 
   3930       var r = jStat.zeros(p, p);
   3931       x = jStat.copy(x);
   3932 
   3933       var i,j,k;
   3934       for(j = 0; j < p; j++){
   3935         r[j][j] = Math.sqrt(sum(range(n).map(function(i){
   3936           return x[i][j] * x[i][j];
   3937         })));
   3938         for(i = 0; i < n; i++){
   3939           x[i][j] = x[i][j] / r[j][j];
   3940         }
   3941         for(k = j+1; k < p; k++){
   3942           r[j][k] = sum(range(n).map(function(i){
   3943             return x[i][j] * x[i][k];
   3944           }));
   3945           for(i = 0; i < n; i++){
   3946             x[i][k] = x[i][k] - x[i][j]*r[j][k];
   3947           }
   3948         }
   3949       }
   3950       return [x, r];
   3951     }
   3952 
   3953     return qr2;
   3954   }()),
   3955 
   3956   lstsq: (function() {
   3957     // solve least squard problem for Ax=b as QR decomposition way if b is
   3958     // [[b1],[b2],[b3]] form will return [[x1],[x2],[x3]] array form solution
   3959     // else b is [b1,b2,b3] form will return [x1,x2,x3] array form solution
   3960     function R_I(A) {
   3961       A = jStat.copy(A);
   3962       var size = A.length;
   3963       var I = jStat.identity(size);
   3964       jStat.arange(size - 1, -1, -1).forEach(function(i) {
   3965         jStat.sliceAssign(
   3966             I, { row: i }, jStat.divide(jStat.slice(I, { row: i }), A[i][i]));
   3967         jStat.sliceAssign(
   3968             A, { row: i }, jStat.divide(jStat.slice(A, { row: i }), A[i][i]));
   3969         jStat.arange(i).forEach(function(j) {
   3970           var c = jStat.multiply(A[j][i], -1);
   3971           var Aj = jStat.slice(A, { row: j });
   3972           var cAi = jStat.multiply(jStat.slice(A, { row: i }), c);
   3973           jStat.sliceAssign(A, { row: j }, jStat.add(Aj, cAi));
   3974           var Ij = jStat.slice(I, { row: j });
   3975           var cIi = jStat.multiply(jStat.slice(I, { row: i }), c);
   3976           jStat.sliceAssign(I, { row: j }, jStat.add(Ij, cIi));
   3977         })
   3978       });
   3979       return I;
   3980     }
   3981 
   3982     function qr_solve(A, b){
   3983       var array_mode = false;
   3984       if (b[0].length === undefined) {
   3985         // [c1,c2,c3] mode
   3986         b = b.map(function(x){ return [x] });
   3987         array_mode = true;
   3988       }
   3989       var QR = jStat.QR(A);
   3990       var Q = QR[0];
   3991       var R = QR[1];
   3992       var attrs = A[0].length;
   3993       var Q1 = jStat.slice(Q,{col:{end:attrs}});
   3994       var R1 = jStat.slice(R,{row:{end:attrs}});
   3995       var RI = R_I(R1);
   3996       var Q2 = jStat.transpose(Q1);
   3997 
   3998       if(Q2[0].length === undefined){
   3999         Q2 = [Q2]; // The confusing jStat.multifly implementation threat nature process again.
   4000       }
   4001 
   4002       var x = jStat.multiply(jStat.multiply(RI, Q2), b);
   4003 
   4004       if(x.length === undefined){
   4005         x = [[x]]; // The confusing jStat.multifly implementation threat nature process again.
   4006       }
   4007 
   4008 
   4009       if (array_mode)
   4010         return x.map(function(i){ return i[0] });
   4011       return x;
   4012     }
   4013 
   4014     return qr_solve;
   4015   }()),
   4016 
   4017   jacobi: function jacobi(a) {
   4018     var condition = 1;
   4019     var n = a.length;
   4020     var e = jStat.identity(n, n);
   4021     var ev = [];
   4022     var b, i, j, p, q, maxim, theta, s;
   4023     // condition === 1 only if tolerance is not reached
   4024     while (condition === 1) {
   4025       maxim = a[0][1];
   4026       p = 0;
   4027       q = 1;
   4028       for (i = 0; i < n; i++) {
   4029         for (j = 0; j < n; j++) {
   4030           if (i != j) {
   4031             if (maxim < Math.abs(a[i][j])) {
   4032               maxim = Math.abs(a[i][j]);
   4033               p = i;
   4034               q = j;
   4035             }
   4036           }
   4037         }
   4038       }
   4039       if (a[p][p] === a[q][q])
   4040         theta = (a[p][q] > 0) ? Math.PI / 4 : -Math.PI / 4;
   4041       else
   4042         theta = Math.atan(2 * a[p][q] / (a[p][p] - a[q][q])) / 2;
   4043       s = jStat.identity(n, n);
   4044       s[p][p] = Math.cos(theta);
   4045       s[p][q] = -Math.sin(theta);
   4046       s[q][p] = Math.sin(theta);
   4047       s[q][q] = Math.cos(theta);
   4048       // eigen vector matrix
   4049       e = jStat.multiply(e, s);
   4050       b = jStat.multiply(jStat.multiply(jStat.inv(s), a), s);
   4051       a = b;
   4052       condition = 0;
   4053       for (i = 1; i < n; i++) {
   4054         for (j = 1; j < n; j++) {
   4055           if (i != j && Math.abs(a[i][j]) > 0.001) {
   4056             condition = 1;
   4057           }
   4058         }
   4059       }
   4060     }
   4061     for (i = 0; i < n; i++) ev.push(a[i][i]);
   4062     //returns both the eigenvalue and eigenmatrix
   4063     return [e, ev];
   4064   },
   4065 
   4066   rungekutta: function rungekutta(f, h, p, t_j, u_j, order) {
   4067     var k1, k2, u_j1, k3, k4;
   4068     if (order === 2) {
   4069       while (t_j <= p) {
   4070         k1 = h * f(t_j, u_j);
   4071         k2 = h * f(t_j + h, u_j + k1);
   4072         u_j1 = u_j + (k1 + k2) / 2;
   4073         u_j = u_j1;
   4074         t_j = t_j + h;
   4075       }
   4076     }
   4077     if (order === 4) {
   4078       while (t_j <= p) {
   4079         k1 = h * f(t_j, u_j);
   4080         k2 = h * f(t_j + h / 2, u_j + k1 / 2);
   4081         k3 = h * f(t_j + h / 2, u_j + k2 / 2);
   4082         k4 = h * f(t_j +h, u_j + k3);
   4083         u_j1 = u_j + (k1 + 2 * k2 + 2 * k3 + k4) / 6;
   4084         u_j = u_j1;
   4085         t_j = t_j + h;
   4086       }
   4087     }
   4088     return u_j;
   4089   },
   4090 
   4091   romberg: function romberg(f, a, b, order) {
   4092     var i = 0;
   4093     var h = (b - a) / 2;
   4094     var x = [];
   4095     var h1 = [];
   4096     var g = [];
   4097     var m, a1, j, k, I;
   4098     while (i < order / 2) {
   4099       I = f(a);
   4100       for (j = a, k = 0; j <= b; j = j + h, k++) x[k] = j;
   4101       m = x.length;
   4102       for (j = 1; j < m - 1; j++) {
   4103         I += (((j % 2) !== 0) ? 4 : 2) * f(x[j]);
   4104       }
   4105       I = (h / 3) * (I + f(b));
   4106       g[i] = I;
   4107       h /= 2;
   4108       i++;
   4109     }
   4110     a1 = g.length;
   4111     m = 1;
   4112     while (a1 !== 1) {
   4113       for (j = 0; j < a1 - 1; j++)
   4114       h1[j] = ((Math.pow(4, m)) * g[j + 1] - g[j]) / (Math.pow(4, m) - 1);
   4115       a1 = h1.length;
   4116       g = h1;
   4117       h1 = [];
   4118       m++;
   4119     }
   4120     return g;
   4121   },
   4122 
   4123   richardson: function richardson(X, f, x, h) {
   4124     function pos(X, x) {
   4125       var i = 0;
   4126       var n = X.length;
   4127       var p;
   4128       for (; i < n; i++)
   4129         if (X[i] === x) p = i;
   4130       return p;
   4131     }
   4132     var h_min = Math.abs(x - X[pos(X, x) + 1]);
   4133     var i = 0;
   4134     var g = [];
   4135     var h1 = [];
   4136     var y1, y2, m, a, j;
   4137     while (h >= h_min) {
   4138       y1 = pos(X, x + h);
   4139       y2 = pos(X, x);
   4140       g[i] = (f[y1] - 2 * f[y2] + f[2 * y2 - y1]) / (h * h);
   4141       h /= 2;
   4142       i++;
   4143     }
   4144     a = g.length;
   4145     m = 1;
   4146     while (a != 1) {
   4147       for (j = 0; j < a - 1; j++)
   4148         h1[j] = ((Math.pow(4, m)) * g[j + 1] - g[j]) / (Math.pow(4, m) - 1);
   4149       a = h1.length;
   4150       g = h1;
   4151       h1 = [];
   4152       m++;
   4153     }
   4154     return g;
   4155   },
   4156 
   4157   simpson: function simpson(f, a, b, n) {
   4158     var h = (b - a) / n;
   4159     var I = f(a);
   4160     var x = [];
   4161     var j = a;
   4162     var k = 0;
   4163     var i = 1;
   4164     var m;
   4165     for (; j <= b; j = j + h, k++)
   4166       x[k] = j;
   4167     m = x.length;
   4168     for (; i < m - 1; i++) {
   4169       I += ((i % 2 !== 0) ? 4 : 2) * f(x[i]);
   4170     }
   4171     return (h / 3) * (I + f(b));
   4172   },
   4173 
   4174   hermite: function hermite(X, F, dF, value) {
   4175     var n = X.length;
   4176     var p = 0;
   4177     var i = 0;
   4178     var l = [];
   4179     var dl = [];
   4180     var A = [];
   4181     var B = [];
   4182     var j;
   4183     for (; i < n; i++) {
   4184       l[i] = 1;
   4185       for (j = 0; j < n; j++) {
   4186         if (i != j) l[i] *= (value - X[j]) / (X[i] - X[j]);
   4187       }
   4188       dl[i] = 0;
   4189       for (j = 0; j < n; j++) {
   4190         if (i != j) dl[i] += 1 / (X [i] - X[j]);
   4191       }
   4192       A[i] = (1 - 2 * (value - X[i]) * dl[i]) * (l[i] * l[i]);
   4193       B[i] = (value - X[i]) * (l[i] * l[i]);
   4194       p += (A[i] * F[i] + B[i] * dF[i]);
   4195     }
   4196     return p;
   4197   },
   4198 
   4199   lagrange: function lagrange(X, F, value) {
   4200     var p = 0;
   4201     var i = 0;
   4202     var j, l;
   4203     var n = X.length;
   4204     for (; i < n; i++) {
   4205       l = F[i];
   4206       for (j = 0; j < n; j++) {
   4207         // calculating the lagrange polynomial L_i
   4208         if (i != j) l *= (value - X[j]) / (X[i] - X[j]);
   4209       }
   4210       // adding the lagrange polynomials found above
   4211       p += l;
   4212     }
   4213     return p;
   4214   },
   4215 
   4216   cubic_spline: function cubic_spline(X, F, value) {
   4217     var n = X.length;
   4218     var i = 0, j;
   4219     var A = [];
   4220     var B = [];
   4221     var alpha = [];
   4222     var c = [];
   4223     var h = [];
   4224     var b = [];
   4225     var d = [];
   4226     for (; i < n - 1; i++)
   4227       h[i] = X[i + 1] - X[i];
   4228     alpha[0] = 0;
   4229     for (i = 1; i < n - 1; i++) {
   4230       alpha[i] = (3 / h[i]) * (F[i + 1] - F[i]) -
   4231           (3 / h[i-1]) * (F[i] - F[i-1]);
   4232     }
   4233     for (i = 1; i < n - 1; i++) {
   4234       A[i] = [];
   4235       B[i] = [];
   4236       A[i][i-1] = h[i-1];
   4237       A[i][i] = 2 * (h[i - 1] + h[i]);
   4238       A[i][i+1] = h[i];
   4239       B[i][0] = alpha[i];
   4240     }
   4241     c = jStat.multiply(jStat.inv(A), B);
   4242     for (j = 0; j < n - 1; j++) {
   4243       b[j] = (F[j + 1] - F[j]) / h[j] - h[j] * (c[j + 1][0] + 2 * c[j][0]) / 3;
   4244       d[j] = (c[j + 1][0] - c[j][0]) / (3 * h[j]);
   4245     }
   4246     for (j = 0; j < n; j++) {
   4247       if (X[j] > value) break;
   4248     }
   4249     j -= 1;
   4250     return F[j] + (value - X[j]) * b[j] + jStat.sq(value-X[j]) *
   4251         c[j] + (value - X[j]) * jStat.sq(value - X[j]) * d[j];
   4252   },
   4253 
   4254   gauss_quadrature: function gauss_quadrature() {
   4255     throw new Error('gauss_quadrature not yet implemented');
   4256   },
   4257 
   4258   PCA: function PCA(X) {
   4259     var m = X.length;
   4260     var n = X[0].length;
   4261     var i = 0;
   4262     var j, temp1;
   4263     var u = [];
   4264     var D = [];
   4265     var result = [];
   4266     var temp2 = [];
   4267     var Y = [];
   4268     var Bt = [];
   4269     var B = [];
   4270     var C = [];
   4271     var V = [];
   4272     var Vt = [];
   4273     for (i = 0; i < m; i++) {
   4274       u[i] = jStat.sum(X[i]) / n;
   4275     }
   4276     for (i = 0; i < n; i++) {
   4277       B[i] = [];
   4278       for(j = 0; j < m; j++) {
   4279         B[i][j] = X[j][i] - u[j];
   4280       }
   4281     }
   4282     B = jStat.transpose(B);
   4283     for (i = 0; i < m; i++) {
   4284       C[i] = [];
   4285       for (j = 0; j < m; j++) {
   4286         C[i][j] = (jStat.dot([B[i]], [B[j]])) / (n - 1);
   4287       }
   4288     }
   4289     result = jStat.jacobi(C);
   4290     V = result[0];
   4291     D = result[1];
   4292     Vt = jStat.transpose(V);
   4293     for (i = 0; i < D.length; i++) {
   4294       for (j = i; j < D.length; j++) {
   4295         if(D[i] < D[j])  {
   4296           temp1 = D[i];
   4297           D[i] = D[j];
   4298           D[j] = temp1;
   4299           temp2 = Vt[i];
   4300           Vt[i] = Vt[j];
   4301           Vt[j] = temp2;
   4302         }
   4303       }
   4304     }
   4305     Bt = jStat.transpose(B);
   4306     for (i = 0; i < m; i++) {
   4307       Y[i] = [];
   4308       for (j = 0; j < Bt.length; j++) {
   4309         Y[i][j] = jStat.dot([Vt[i]], [Bt[j]]);
   4310       }
   4311     }
   4312     return [X, D, Vt, Y];
   4313   }
   4314 });
   4315 
   4316 // extend jStat.fn with methods that require one argument
   4317 (function(funcs) {
   4318   for (var i = 0; i < funcs.length; i++) (function(passfunc) {
   4319     jStat.fn[passfunc] = function(arg, func) {
   4320       var tmpthis = this;
   4321       // check for callback
   4322       if (func) {
   4323         setTimeout(function() {
   4324           func.call(tmpthis, jStat.fn[passfunc].call(tmpthis, arg));
   4325         }, 15);
   4326         return this;
   4327       }
   4328       if (typeof jStat[passfunc](this, arg) === 'number')
   4329         return jStat[passfunc](this, arg);
   4330       else
   4331         return jStat(jStat[passfunc](this, arg));
   4332     };
   4333   }(funcs[i]));
   4334 }('add divide multiply subtract dot pow exp log abs norm angle'.split(' ')));
   4335 
   4336 }(jStat, Math));
   4337 (function(jStat, Math) {
   4338 
   4339 var slice = [].slice;
   4340 var isNumber = jStat.utils.isNumber;
   4341 var isArray = jStat.utils.isArray;
   4342 
   4343 // flag==true denotes use of sample standard deviation
   4344 // Z Statistics
   4345 jStat.extend({
   4346   // 2 different parameter lists:
   4347   // (value, mean, sd)
   4348   // (value, array, flag)
   4349   zscore: function zscore() {
   4350     var args = slice.call(arguments);
   4351     if (isNumber(args[1])) {
   4352       return (args[0] - args[1]) / args[2];
   4353     }
   4354     return (args[0] - jStat.mean(args[1])) / jStat.stdev(args[1], args[2]);
   4355   },
   4356 
   4357   // 3 different paramter lists:
   4358   // (value, mean, sd, sides)
   4359   // (zscore, sides)
   4360   // (value, array, sides, flag)
   4361   ztest: function ztest() {
   4362     var args = slice.call(arguments);
   4363     var z;
   4364     if (isArray(args[1])) {
   4365       // (value, array, sides, flag)
   4366       z = jStat.zscore(args[0],args[1],args[3]);
   4367       return (args[2] === 1) ?
   4368         (jStat.normal.cdf(-Math.abs(z), 0, 1)) :
   4369         (jStat.normal.cdf(-Math.abs(z), 0, 1)*2);
   4370     } else {
   4371       if (args.length > 2) {
   4372         // (value, mean, sd, sides)
   4373         z = jStat.zscore(args[0],args[1],args[2]);
   4374         return (args[3] === 1) ?
   4375           (jStat.normal.cdf(-Math.abs(z),0,1)) :
   4376           (jStat.normal.cdf(-Math.abs(z),0,1)* 2);
   4377       } else {
   4378         // (zscore, sides)
   4379         z = args[0];
   4380         return (args[1] === 1) ?
   4381           (jStat.normal.cdf(-Math.abs(z),0,1)) :
   4382           (jStat.normal.cdf(-Math.abs(z),0,1)*2);
   4383       }
   4384     }
   4385   }
   4386 });
   4387 
   4388 jStat.extend(jStat.fn, {
   4389   zscore: function zscore(value, flag) {
   4390     return (value - this.mean()) / this.stdev(flag);
   4391   },
   4392 
   4393   ztest: function ztest(value, sides, flag) {
   4394     var zscore = Math.abs(this.zscore(value, flag));
   4395     return (sides === 1) ?
   4396       (jStat.normal.cdf(-zscore, 0, 1)) :
   4397       (jStat.normal.cdf(-zscore, 0, 1) * 2);
   4398   }
   4399 });
   4400 
   4401 // T Statistics
   4402 jStat.extend({
   4403   // 2 parameter lists
   4404   // (value, mean, sd, n)
   4405   // (value, array)
   4406   tscore: function tscore() {
   4407     var args = slice.call(arguments);
   4408     return (args.length === 4) ?
   4409       ((args[0] - args[1]) / (args[2] / Math.sqrt(args[3]))) :
   4410       ((args[0] - jStat.mean(args[1])) /
   4411        (jStat.stdev(args[1], true) / Math.sqrt(args[1].length)));
   4412   },
   4413 
   4414   // 3 different paramter lists:
   4415   // (value, mean, sd, n, sides)
   4416   // (tscore, n, sides)
   4417   // (value, array, sides)
   4418   ttest: function ttest() {
   4419     var args = slice.call(arguments);
   4420     var tscore;
   4421     if (args.length === 5) {
   4422       tscore = Math.abs(jStat.tscore(args[0], args[1], args[2], args[3]));
   4423       return (args[4] === 1) ?
   4424         (jStat.studentt.cdf(-tscore, args[3]-1)) :
   4425         (jStat.studentt.cdf(-tscore, args[3]-1)*2);
   4426     }
   4427     if (isNumber(args[1])) {
   4428       tscore = Math.abs(args[0])
   4429       return (args[2] == 1) ?
   4430         (jStat.studentt.cdf(-tscore, args[1]-1)) :
   4431         (jStat.studentt.cdf(-tscore, args[1]-1) * 2);
   4432     }
   4433     tscore = Math.abs(jStat.tscore(args[0], args[1]))
   4434     return (args[2] == 1) ?
   4435       (jStat.studentt.cdf(-tscore, args[1].length-1)) :
   4436       (jStat.studentt.cdf(-tscore, args[1].length-1) * 2);
   4437   }
   4438 });
   4439 
   4440 jStat.extend(jStat.fn, {
   4441   tscore: function tscore(value) {
   4442     return (value - this.mean()) / (this.stdev(true) / Math.sqrt(this.cols()));
   4443   },
   4444 
   4445   ttest: function ttest(value, sides) {
   4446     return (sides === 1) ?
   4447       (1 - jStat.studentt.cdf(Math.abs(this.tscore(value)), this.cols()-1)) :
   4448       (jStat.studentt.cdf(-Math.abs(this.tscore(value)), this.cols()-1)*2);
   4449   }
   4450 });
   4451 
   4452 // F Statistics
   4453 jStat.extend({
   4454   // Paramter list is as follows:
   4455   // (array1, array2, array3, ...)
   4456   // or it is an array of arrays
   4457   // array of arrays conversion
   4458   anovafscore: function anovafscore() {
   4459     var args = slice.call(arguments),
   4460     expVar, sample, sampMean, sampSampMean, tmpargs, unexpVar, i, j;
   4461     if (args.length === 1) {
   4462       tmpargs = new Array(args[0].length);
   4463       for (i = 0; i < args[0].length; i++) {
   4464         tmpargs[i] = args[0][i];
   4465       }
   4466       args = tmpargs;
   4467     }
   4468     // Builds sample array
   4469     sample = new Array();
   4470     for (i = 0; i < args.length; i++) {
   4471       sample = sample.concat(args[i]);
   4472     }
   4473     sampMean = jStat.mean(sample);
   4474     // Computes the explained variance
   4475     expVar = 0;
   4476     for (i = 0; i < args.length; i++) {
   4477       expVar = expVar + args[i].length * Math.pow(jStat.mean(args[i]) - sampMean, 2);
   4478     }
   4479     expVar /= (args.length - 1);
   4480     // Computes unexplained variance
   4481     unexpVar = 0;
   4482     for (i = 0; i < args.length; i++) {
   4483       sampSampMean = jStat.mean(args[i]);
   4484       for (j = 0; j < args[i].length; j++) {
   4485         unexpVar += Math.pow(args[i][j] - sampSampMean, 2);
   4486       }
   4487     }
   4488     unexpVar /= (sample.length - args.length);
   4489     return expVar / unexpVar;
   4490   },
   4491 
   4492   // 2 different paramter setups
   4493   // (array1, array2, array3, ...)
   4494   // (anovafscore, df1, df2)
   4495   anovaftest: function anovaftest() {
   4496     var args = slice.call(arguments),
   4497     df1, df2, n, i;
   4498     if (isNumber(args[0])) {
   4499       return 1 - jStat.centralF.cdf(args[0], args[1], args[2]);
   4500     }
   4501     var anovafscore = jStat.anovafscore(args);
   4502     df1 = args.length - 1;
   4503     n = 0;
   4504     for (i = 0; i < args.length; i++) {
   4505       n = n + args[i].length;
   4506     }
   4507     df2 = n - df1 - 1;
   4508     return 1 - jStat.centralF.cdf(anovafscore, df1, df2);
   4509   },
   4510 
   4511   ftest: function ftest(fscore, df1, df2) {
   4512     return 1 - jStat.centralF.cdf(fscore, df1, df2);
   4513   }
   4514 });
   4515 
   4516 jStat.extend(jStat.fn, {
   4517   anovafscore: function anovafscore() {
   4518     return jStat.anovafscore(this.toArray());
   4519   },
   4520 
   4521   anovaftes: function anovaftes() {
   4522     var n = 0;
   4523     var i;
   4524     for (i = 0; i < this.length; i++) {
   4525       n = n + this[i].length;
   4526     }
   4527     return jStat.ftest(this.anovafscore(), this.length - 1, n - this.length);
   4528   }
   4529 });
   4530 
   4531 // Tukey's range test
   4532 jStat.extend({
   4533   // 2 parameter lists
   4534   // (mean1, mean2, n1, n2, sd)
   4535   // (array1, array2, sd)
   4536   qscore: function qscore() {
   4537     var args = slice.call(arguments);
   4538     var mean1, mean2, n1, n2, sd;
   4539     if (isNumber(args[0])) {
   4540         mean1 = args[0];
   4541         mean2 = args[1];
   4542         n1 = args[2];
   4543         n2 = args[3];
   4544         sd = args[4];
   4545     } else {
   4546         mean1 = jStat.mean(args[0]);
   4547         mean2 = jStat.mean(args[1]);
   4548         n1 = args[0].length;
   4549         n2 = args[1].length;
   4550         sd = args[2];
   4551     }
   4552     return Math.abs(mean1 - mean2) / (sd * Math.sqrt((1 / n1 + 1 / n2) / 2));
   4553   },
   4554 
   4555   // 3 different parameter lists:
   4556   // (qscore, n, k)
   4557   // (mean1, mean2, n1, n2, sd, n, k)
   4558   // (array1, array2, sd, n, k)
   4559   qtest: function qtest() {
   4560     var args = slice.call(arguments);
   4561 
   4562     var qscore;
   4563     if (args.length === 3) {
   4564       qscore = args[0];
   4565       args = args.slice(1);
   4566     } else if (args.length === 7) {
   4567       qscore = jStat.qscore(args[0], args[1], args[2], args[3], args[4]);
   4568       args = args.slice(5);
   4569     } else {
   4570       qscore = jStat.qscore(args[0], args[1], args[2]);
   4571       args = args.slice(3);
   4572     }
   4573 
   4574     var n = args[0];
   4575     var k = args[1];
   4576 
   4577     return 1 - jStat.tukey.cdf(qscore, k, n - k);
   4578   },
   4579 
   4580   tukeyhsd: function tukeyhsd(arrays) {
   4581     var sd = jStat.pooledstdev(arrays);
   4582     var means = arrays.map(function (arr) {return jStat.mean(arr);});
   4583     var n = arrays.reduce(function (n, arr) {return n + arr.length;}, 0);
   4584 
   4585     var results = [];
   4586     for (var i = 0; i < arrays.length; ++i) {
   4587         for (var j = i + 1; j < arrays.length; ++j) {
   4588             var p = jStat.qtest(means[i], means[j], arrays[i].length, arrays[j].length, sd, n, arrays.length);
   4589             results.push([[i, j], p]);
   4590         }
   4591     }
   4592 
   4593     return results;
   4594   }
   4595 });
   4596 
   4597 // Error Bounds
   4598 jStat.extend({
   4599   // 2 different parameter setups
   4600   // (value, alpha, sd, n)
   4601   // (value, alpha, array)
   4602   normalci: function normalci() {
   4603     var args = slice.call(arguments),
   4604     ans = new Array(2),
   4605     change;
   4606     if (args.length === 4) {
   4607       change = Math.abs(jStat.normal.inv(args[1] / 2, 0, 1) *
   4608                         args[2] / Math.sqrt(args[3]));
   4609     } else {
   4610       change = Math.abs(jStat.normal.inv(args[1] / 2, 0, 1) *
   4611                         jStat.stdev(args[2]) / Math.sqrt(args[2].length));
   4612     }
   4613     ans[0] = args[0] - change;
   4614     ans[1] = args[0] + change;
   4615     return ans;
   4616   },
   4617 
   4618   // 2 different parameter setups
   4619   // (value, alpha, sd, n)
   4620   // (value, alpha, array)
   4621   tci: function tci() {
   4622     var args = slice.call(arguments),
   4623     ans = new Array(2),
   4624     change;
   4625     if (args.length === 4) {
   4626       change = Math.abs(jStat.studentt.inv(args[1] / 2, args[3] - 1) *
   4627                         args[2] / Math.sqrt(args[3]));
   4628     } else {
   4629       change = Math.abs(jStat.studentt.inv(args[1] / 2, args[2].length - 1) *
   4630                         jStat.stdev(args[2], true) / Math.sqrt(args[2].length));
   4631     }
   4632     ans[0] = args[0] - change;
   4633     ans[1] = args[0] + change;
   4634     return ans;
   4635   },
   4636 
   4637   significant: function significant(pvalue, alpha) {
   4638     return pvalue < alpha;
   4639   }
   4640 });
   4641 
   4642 jStat.extend(jStat.fn, {
   4643   normalci: function normalci(value, alpha) {
   4644     return jStat.normalci(value, alpha, this.toArray());
   4645   },
   4646 
   4647   tci: function tci(value, alpha) {
   4648     return jStat.tci(value, alpha, this.toArray());
   4649   }
   4650 });
   4651 
   4652 // internal method for calculating the z-score for a difference of proportions test
   4653 function differenceOfProportions(p1, n1, p2, n2) {
   4654   if (p1 > 1 || p2 > 1 || p1 <= 0 || p2 <= 0) {
   4655     throw new Error("Proportions should be greater than 0 and less than 1")
   4656   }
   4657   var pooled = (p1 * n1 + p2 * n2) / (n1 + n2);
   4658   var se = Math.sqrt(pooled * (1 - pooled) * ((1/n1) + (1/n2)));
   4659   return (p1 - p2) / se;
   4660 }
   4661 
   4662 // Difference of Proportions
   4663 jStat.extend(jStat.fn, {
   4664   oneSidedDifferenceOfProportions: function oneSidedDifferenceOfProportions(p1, n1, p2, n2) {
   4665     var z = differenceOfProportions(p1, n1, p2, n2);
   4666     return jStat.ztest(z, 1);
   4667   },
   4668 
   4669   twoSidedDifferenceOfProportions: function twoSidedDifferenceOfProportions(p1, n1, p2, n2) {
   4670     var z = differenceOfProportions(p1, n1, p2, n2);
   4671     return jStat.ztest(z, 2);
   4672   }
   4673 });
   4674 
   4675 }(jStat, Math));
   4676 jStat.models = (function(){
   4677   function sub_regress(exog) {
   4678     var var_count = exog[0].length;
   4679     var modelList = jStat.arange(var_count).map(function(endog_index) {
   4680       var exog_index =
   4681           jStat.arange(var_count).filter(function(i){return i!==endog_index});
   4682       return ols(jStat.col(exog, endog_index).map(function(x){ return x[0] }),
   4683                  jStat.col(exog, exog_index))
   4684     });
   4685     return modelList;
   4686   }
   4687 
   4688   // do OLS model regress
   4689   // exog have include const columns ,it will not generate it .In fact, exog is
   4690   // "design matrix" look at
   4691   //https://en.wikipedia.org/wiki/Design_matrix
   4692   function ols(endog, exog) {
   4693     var nobs = endog.length;
   4694     var df_model = exog[0].length - 1;
   4695     var df_resid = nobs-df_model - 1;
   4696     var coef = jStat.lstsq(exog, endog);
   4697     var predict =
   4698         jStat.multiply(exog, coef.map(function(x) { return [x] }))
   4699             .map(function(p) { return p[0] });
   4700     var resid = jStat.subtract(endog, predict);
   4701     var ybar = jStat.mean(endog);
   4702     // constant cause problem
   4703     // var SST = jStat.sum(endog.map(function(y) {
   4704     //   return Math.pow(y-ybar,2);
   4705     // }));
   4706     var SSE = jStat.sum(predict.map(function(f) {
   4707       return Math.pow(f - ybar, 2);
   4708     }));
   4709     var SSR = jStat.sum(endog.map(function(y, i) {
   4710       return Math.pow(y - predict[i], 2);
   4711     }));
   4712     var SST = SSE + SSR;
   4713     var R2 = (SSE / SST);
   4714     return {
   4715         exog:exog,
   4716         endog:endog,
   4717         nobs:nobs,
   4718         df_model:df_model,
   4719         df_resid:df_resid,
   4720         coef:coef,
   4721         predict:predict,
   4722         resid:resid,
   4723         ybar:ybar,
   4724         SST:SST,
   4725         SSE:SSE,
   4726         SSR:SSR,
   4727         R2:R2
   4728     };
   4729   }
   4730 
   4731   // H0: b_I=0
   4732   // H1: b_I!=0
   4733   function t_test(model) {
   4734     var subModelList = sub_regress(model.exog);
   4735     //var sigmaHat=jStat.stdev(model.resid);
   4736     var sigmaHat = Math.sqrt(model.SSR / (model.df_resid));
   4737     var seBetaHat = subModelList.map(function(mod) {
   4738       var SST = mod.SST;
   4739       var R2 = mod.R2;
   4740       return sigmaHat / Math.sqrt(SST * (1 - R2));
   4741     });
   4742     var tStatistic = model.coef.map(function(coef, i) {
   4743       return (coef - 0) / seBetaHat[i];
   4744     });
   4745     var pValue = tStatistic.map(function(t) {
   4746       var leftppf = jStat.studentt.cdf(t, model.df_resid);
   4747       return (leftppf > 0.5 ? 1 - leftppf : leftppf) * 2;
   4748     });
   4749     var c = jStat.studentt.inv(0.975, model.df_resid);
   4750     var interval95 = model.coef.map(function(coef, i) {
   4751       var d = c * seBetaHat[i];
   4752       return [coef - d, coef + d];
   4753     })
   4754     return {
   4755         se: seBetaHat,
   4756         t: tStatistic,
   4757         p: pValue,
   4758         sigmaHat: sigmaHat,
   4759         interval95: interval95
   4760     };
   4761   }
   4762 
   4763   function F_test(model) {
   4764     var F_statistic =
   4765         (model.R2 / model.df_model) / ((1 - model.R2) / model.df_resid);
   4766     var fcdf = function(x, n1, n2) {
   4767       return jStat.beta.cdf(x / (n2 / n1 + x), n1 / 2, n2 / 2)
   4768     }
   4769     var pvalue = 1 - fcdf(F_statistic, model.df_model, model.df_resid);
   4770     return { F_statistic: F_statistic, pvalue: pvalue };
   4771   }
   4772 
   4773   function ols_wrap(endog, exog) {
   4774     var model = ols(endog,exog);
   4775     var ttest = t_test(model);
   4776     var ftest = F_test(model);
   4777     // Provide the Wherry / Ezekiel / McNemar / Cohen Adjusted R^2
   4778     // Which matches the 'adjusted R^2' provided by R's lm package
   4779     var adjust_R2 =
   4780         1 - (1 - model.R2) * ((model.nobs - 1) / (model.df_resid));
   4781     model.t = ttest;
   4782     model.f = ftest;
   4783     model.adjust_R2 = adjust_R2;
   4784     return model;
   4785   }
   4786 
   4787   return { ols: ols_wrap };
   4788 })();
   4789 //To regress, simply build X matrix
   4790 //(append column of 1's) using
   4791 //buildxmatrix and build the Y
   4792 //matrix using buildymatrix
   4793 //(simply the transpose)
   4794 //and run regress.
   4795 
   4796 
   4797 
   4798 //Regressions
   4799 
   4800 jStat.extend({
   4801   buildxmatrix: function buildxmatrix(){
   4802     //Parameters will be passed in as such
   4803     //(array1,array2,array3,...)
   4804     //as (x1,x2,x3,...)
   4805     //needs to be (1,x1,x2,x3,...)
   4806     var matrixRows = new Array(arguments.length);
   4807     for(var i=0;i<arguments.length;i++){
   4808       var array = [1];
   4809       matrixRows[i]= array.concat(arguments[i]);
   4810     }
   4811     return jStat(matrixRows);
   4812 
   4813   },
   4814 
   4815   builddxmatrix: function builddxmatrix() {
   4816     //Paramters will be passed in as such
   4817     //([array1,array2,...]
   4818     var matrixRows = new Array(arguments[0].length);
   4819     for(var i=0;i<arguments[0].length;i++){
   4820       var array = [1]
   4821       matrixRows[i]= array.concat(arguments[0][i]);
   4822     }
   4823     return jStat(matrixRows);
   4824 
   4825   },
   4826 
   4827   buildjxmatrix: function buildjxmatrix(jMat) {
   4828     //Builds from jStat Matrix
   4829     var pass = new Array(jMat.length)
   4830     for(var i=0;i<jMat.length;i++){
   4831       pass[i] = jMat[i];
   4832     }
   4833     return jStat.builddxmatrix(pass);
   4834 
   4835   },
   4836 
   4837   buildymatrix: function buildymatrix(array){
   4838     return jStat(array).transpose();
   4839   },
   4840 
   4841   buildjymatrix: function buildjymatrix(jMat){
   4842     return jMat.transpose();
   4843   },
   4844 
   4845   matrixmult: function matrixmult(A,B){
   4846     var i, j, k, result, sum;
   4847     if (A.cols() == B.rows()) {
   4848       if(B.rows()>1){
   4849         result = [];
   4850         for (i = 0; i < A.rows(); i++) {
   4851           result[i] = [];
   4852           for (j = 0; j < B.cols(); j++) {
   4853             sum = 0;
   4854             for (k = 0; k < A.cols(); k++) {
   4855               sum += A.toArray()[i][k] * B.toArray()[k][j];
   4856             }
   4857             result[i][j] = sum;
   4858           }
   4859         }
   4860         return jStat(result);
   4861       }
   4862       result = [];
   4863       for (i = 0; i < A.rows(); i++) {
   4864         result[i] = [];
   4865         for (j = 0; j < B.cols(); j++) {
   4866           sum = 0;
   4867           for (k = 0; k < A.cols(); k++) {
   4868             sum += A.toArray()[i][k] * B.toArray()[j];
   4869           }
   4870           result[i][j] = sum;
   4871         }
   4872       }
   4873       return jStat(result);
   4874     }
   4875   },
   4876 
   4877   //regress and regresst to be fixed
   4878 
   4879   regress: function regress(jMatX,jMatY){
   4880     //print("regressin!");
   4881     //print(jMatX.toArray());
   4882     var innerinv = jStat.xtranspxinv(jMatX);
   4883     //print(innerinv);
   4884     var xtransp = jMatX.transpose();
   4885     var next = jStat.matrixmult(jStat(innerinv),xtransp);
   4886     return jStat.matrixmult(next,jMatY);
   4887 
   4888   },
   4889 
   4890   regresst: function regresst(jMatX,jMatY,sides){
   4891     var beta = jStat.regress(jMatX,jMatY);
   4892 
   4893     var compile = {};
   4894     compile.anova = {};
   4895     var jMatYBar = jStat.jMatYBar(jMatX, beta);
   4896     compile.yBar = jMatYBar;
   4897     var yAverage = jMatY.mean();
   4898     compile.anova.residuals = jStat.residuals(jMatY, jMatYBar);
   4899 
   4900     compile.anova.ssr = jStat.ssr(jMatYBar, yAverage);
   4901     compile.anova.msr = compile.anova.ssr / (jMatX[0].length - 1);
   4902 
   4903     compile.anova.sse = jStat.sse(jMatY, jMatYBar);
   4904     compile.anova.mse =
   4905         compile.anova.sse / (jMatY.length - (jMatX[0].length - 1) - 1);
   4906 
   4907     compile.anova.sst = jStat.sst(jMatY, yAverage);
   4908     compile.anova.mst = compile.anova.sst / (jMatY.length - 1);
   4909 
   4910     compile.anova.r2 = 1 - (compile.anova.sse / compile.anova.sst);
   4911     if (compile.anova.r2 < 0) compile.anova.r2 = 0;
   4912 
   4913     compile.anova.fratio = compile.anova.msr / compile.anova.mse;
   4914     compile.anova.pvalue =
   4915         jStat.anovaftest(compile.anova.fratio,
   4916                          jMatX[0].length - 1,
   4917                          jMatY.length - (jMatX[0].length - 1) - 1);
   4918 
   4919     compile.anova.rmse = Math.sqrt(compile.anova.mse);
   4920 
   4921     compile.anova.r2adj = 1 - (compile.anova.mse / compile.anova.mst);
   4922     if (compile.anova.r2adj < 0) compile.anova.r2adj = 0;
   4923 
   4924     compile.stats = new Array(jMatX[0].length);
   4925     var covar = jStat.xtranspxinv(jMatX);
   4926     var sds, ts, ps;
   4927 
   4928     for(var i=0; i<beta.length;i++){
   4929       sds=Math.sqrt(compile.anova.mse * Math.abs(covar[i][i]));
   4930       ts= Math.abs(beta[i] / sds);
   4931       ps= jStat.ttest(ts, jMatY.length - jMatX[0].length - 1, sides);
   4932 
   4933       compile.stats[i]=[beta[i], sds, ts, ps];
   4934     }
   4935 
   4936     compile.regress = beta;
   4937     return compile;
   4938   },
   4939 
   4940   xtranspx: function xtranspx(jMatX){
   4941     return jStat.matrixmult(jMatX.transpose(),jMatX);
   4942   },
   4943 
   4944 
   4945   xtranspxinv: function xtranspxinv(jMatX){
   4946     var inner = jStat.matrixmult(jMatX.transpose(),jMatX);
   4947     var innerinv = jStat.inv(inner);
   4948     return innerinv;
   4949   },
   4950 
   4951   jMatYBar: function jMatYBar(jMatX, beta) {
   4952     var yBar = jStat.matrixmult(jMatX, beta);
   4953     return new jStat(yBar);
   4954   },
   4955 
   4956   residuals: function residuals(jMatY, jMatYBar) {
   4957     return jStat.matrixsubtract(jMatY, jMatYBar);
   4958   },
   4959 
   4960   ssr: function ssr(jMatYBar, yAverage) {
   4961     var ssr = 0;
   4962     for(var i = 0; i < jMatYBar.length; i++) {
   4963       ssr += Math.pow(jMatYBar[i] - yAverage, 2);
   4964     }
   4965     return ssr;
   4966   },
   4967 
   4968   sse: function sse(jMatY, jMatYBar) {
   4969     var sse = 0;
   4970     for(var i = 0; i < jMatY.length; i++) {
   4971       sse += Math.pow(jMatY[i] - jMatYBar[i], 2);
   4972     }
   4973     return sse;
   4974   },
   4975 
   4976   sst: function sst(jMatY, yAverage) {
   4977     var sst = 0;
   4978     for(var i = 0; i < jMatY.length; i++) {
   4979       sst += Math.pow(jMatY[i] - yAverage, 2);
   4980     }
   4981     return sst;
   4982   },
   4983 
   4984   matrixsubtract: function matrixsubtract(A,B){
   4985     var ans = new Array(A.length);
   4986     for(var i=0;i<A.length;i++){
   4987       ans[i] = new Array(A[i].length);
   4988       for(var j=0;j<A[i].length;j++){
   4989         ans[i][j]=A[i][j]-B[i][j];
   4990       }
   4991     }
   4992     return jStat(ans);
   4993   }
   4994 });
   4995   // Make it compatible with previous version.
   4996   jStat.jStat = jStat;
   4997 
   4998   return jStat;
   4999 });