Comparing version 0.0.2 to 0.4.0
/** | ||
* numbers.js | ||
* http://github.com/sjkaliski/numbers.js | ||
* | ||
* top level management of numbers extensions | ||
* Copyright 2012 Stephen Kaliski | ||
* | ||
* (C) 2012 Steve Kaliski | ||
* MIT License | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
var numbers = exports; | ||
@@ -16,6 +27,8 @@ | ||
numbers.calculus = require('./numbers/calculus'); | ||
numbers.complex = require('./numbers/complex'); | ||
numbers.dsp = require('./numbers/dsp'); | ||
numbers.matrix = require('./numbers/matrix'); | ||
numbers.prime = require('./numbers/prime'); | ||
numbers.statistic = require('./numbers/statistic'); | ||
numbers.useless = require('./numbers/useless'); | ||
numbers.generate = require('./numbers/generators'); | ||
@@ -22,0 +35,0 @@ /** |
@@ -0,17 +1,38 @@ | ||
/** | ||
* basic.js | ||
* http://github.com/sjkaliski/numbers.js | ||
* | ||
* Copyright 2012 Stephen Kaliski | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
var basic = exports; | ||
/** | ||
* Determine the summation of numbers in a given array | ||
* Determine the summation of numbers in a given array. | ||
* | ||
* @param {Array} collection of numbers | ||
* @return {Number} sum of numbers in array | ||
* @param {Array} collection of numbers. | ||
* @return {Number} sum of numbers in array. | ||
*/ | ||
basic.addition = function (arr) { | ||
basic.sum = function (arr) { | ||
if (Object.prototype.toString.call(arr) === '[object Array]') { | ||
var total = 0; | ||
for (var i = 0 ; i < arr.length ; i++) { | ||
if (typeof(arr[i]) === 'number') | ||
if (typeof(arr[i]) === 'number') { | ||
total = total + arr[i]; | ||
else | ||
} else { | ||
throw new Error('All elements in array must be numbers'); | ||
} | ||
} | ||
@@ -29,4 +50,4 @@ return total; | ||
* | ||
* @param {Array} collection of numbers | ||
* @return {Number} difference | ||
* @param {Array} collection of numbers. | ||
* @return {Number} difference. | ||
*/ | ||
@@ -37,6 +58,7 @@ basic.subtraction = function (arr) { | ||
for (var i = arr.length - 2; i >= 0; i--) { | ||
if (typeof(arr[i]) === 'number') | ||
if (typeof(arr[i]) === 'number') { | ||
total -= arr[i]; | ||
else | ||
} else { | ||
throw new Error('All elements in array must be numbers'); | ||
} | ||
} | ||
@@ -50,6 +72,6 @@ return total; | ||
/** | ||
* Product of all elements in an array | ||
* Product of all elements in an array. | ||
* | ||
* @param {Array} collection of numbers | ||
* @return {Number} product | ||
* @param {Array} collection of numbers. | ||
* @return {Number} product. | ||
*/ | ||
@@ -59,7 +81,8 @@ basic.product = function (arr) { | ||
var total = arr[0]; | ||
for (var i = 1; i < arr.length; i++) { | ||
if (typeof(arr[i]) === 'number') | ||
for (var i = 1, length = arr.length; i < length; i++) { | ||
if (typeof(arr[i]) === 'number') { | ||
total = total * arr[i]; | ||
else | ||
} else { | ||
throw new Error('All elements in array must be numbers'); | ||
} | ||
} | ||
@@ -73,20 +96,48 @@ return total; | ||
/** | ||
* Factorial for some integer | ||
* Return the square of any value. | ||
* | ||
* @param {Number} integer | ||
* @return {Number} result | ||
* @param {Number} number | ||
* @return {Number} square of number | ||
*/ | ||
basic.factorial = function (num) { | ||
basic.square = function (num) { | ||
return num * num; | ||
}; | ||
/** | ||
* Calculate the binomial coefficient (n choose k) | ||
* | ||
* @param {Number} available choices | ||
* @param {Number} number chosen | ||
* @return {Number} number of possible choices | ||
*/ | ||
basic.binomial = function (n, k) { | ||
var arr = []; | ||
function _factorial(n) { | ||
if (n === 0 || n === 1) return 1; | ||
function _binomial (n, k) { | ||
if (n >= 0 && k === 0) return 1; | ||
if (n === 0 && k > 0) return 0; | ||
if (arr[n] && arr[n][k] > 0) return arr[n][k]; | ||
if (!arr[n]) arr[n] = []; | ||
if (arr[n] > 0) return arr[n]; | ||
return arr[n][k] = _binomial(n - 1, k - 1) + _binomial(n - 1, k); | ||
} | ||
else return arr[n] = _factorial(n - 1) * n; | ||
return _binomial(n, k); | ||
}; | ||
/** | ||
* Factorial for some integer. | ||
* | ||
* @param {Number} integer. | ||
* @return {Number} result. | ||
*/ | ||
basic.factorial = function (num){ | ||
var i = 2, o = 1; | ||
while (i <= num) { | ||
o *= i++; | ||
} | ||
return _factorial(num); | ||
return o; | ||
}; | ||
@@ -96,31 +147,20 @@ | ||
* Calculate the greastest common divisor amongst two integers. | ||
* | ||
* @param {Number} number A | ||
* @param {Number} number B | ||
* @return {Number} greatest common divisor for integers A, B | ||
* Taken from Ratio.js https://github.com/LarryBattle/Ratio.js | ||
* | ||
* @param {Number} number A. | ||
* @param {Number} number B. | ||
* @return {Number} greatest common divisor for integers A, B. | ||
*/ | ||
basic.gcd = function (num1, num2) { | ||
var result; | ||
if (num1 > num2) { | ||
for (var i = 0 ; i <= num2 ; i++) { | ||
if (num2 % i === 0) { | ||
if (num1 % i === 0) { | ||
result = i; | ||
} | ||
} | ||
} | ||
return result; | ||
} else if (num2 > num1) { | ||
for (var j = 0 ; j <= num2 ; j++) { | ||
if (num1 % j === 0) { | ||
if (num2 % j === 0) { | ||
result = j; | ||
} | ||
} | ||
} | ||
return result; | ||
} else { | ||
result = num1 * num2 / num1; | ||
return result; | ||
basic.gcd = function (a, b) { | ||
var c; | ||
b = (+b && +a) ? +b : 0; | ||
a = b ? a : 1; | ||
while (b) { | ||
c = a % b; | ||
a = b; | ||
b = c; | ||
} | ||
return Math.abs(a); | ||
}; | ||
@@ -131,8 +171,8 @@ | ||
* | ||
* @param {Number} number A | ||
* @param {Number} number B | ||
* @return {Number} least common multiple for integers A, B | ||
* @param {Number} number A. | ||
* @param {Number} number B. | ||
* @return {Number} least common multiple for integers A, B. | ||
*/ | ||
basic.lcm = function (num1, num2) { | ||
return Math.abs(num1 * num2) / basic.gcd(num1,num2); | ||
return Math.abs(num1 * num2) / basic.gcd(num1, num2); | ||
}; | ||
@@ -143,11 +183,20 @@ | ||
* | ||
* @param {Array} set of values to select from | ||
* @param {Number} quantity of elements to retrieve | ||
* @return {Array} random elements | ||
* @param {Array} set of values to select from. | ||
* @param {Number} quantity of elements to retrieve. | ||
* @param {Boolean} allow the same number to be returned twice. | ||
* @return {Array} random elements. | ||
*/ | ||
basic.random = function (arr, quant) { | ||
if (arr.length <= quant){ | ||
basic.random = function (arr, quant, allowDuplicates) { | ||
if (arr.length === 0){ | ||
throw new Error('Empty array'); | ||
} else if (quant > arr.length && !allowDuplicates){ | ||
throw new Error('Quantity requested exceeds size of array'); | ||
} else if (arr.length === 0){ | ||
throw new Error('Empty array'); | ||
} | ||
if (allowDuplicates === true) { | ||
var result = [], i; | ||
for (i = 0; i < quant; i++) { | ||
result[i] = arr[Math.floor(Math.random() * arr.length)]; | ||
} | ||
return result; | ||
} else { | ||
@@ -159,6 +208,6 @@ return basic.shuffle(arr).slice(0, quant); | ||
/** | ||
* Shuffle an array, in place | ||
* Shuffle an array, in place. | ||
* | ||
* @param {Array} array to be shuffled | ||
* @return {Array} shuffled array | ||
* @param {Array} array to be shuffled. | ||
* @return {Array} shuffled array. | ||
*/ | ||
@@ -178,1 +227,157 @@ basic.shuffle = function (array) { | ||
}; | ||
/** | ||
* Find maximum value in an array. | ||
* | ||
* @param {Array} array to be traversed. | ||
* @return {Number} maximum value in the array. | ||
*/ | ||
basic.max = function (array) { | ||
return Math.max.apply(Math, array); | ||
}; | ||
/** | ||
* Find minimum value in an array. | ||
* | ||
* @param {Array} array to be traversed. | ||
* @return {Number} minimum value in the array. | ||
*/ | ||
basic.min = function (array) { | ||
return Math.min.apply(Math, array); | ||
}; | ||
/** | ||
* Create a range of numbers. | ||
* | ||
* @param {Number} The start of the range. | ||
* @param {Number} The end of the range. | ||
* @return {Array} An array containing numbers within the range. | ||
*/ | ||
basic.range = function (start, stop, step) { | ||
var array, i = 0, len; | ||
if (arguments.length <= 1) { | ||
stop = start || 0; | ||
start = 0; | ||
} | ||
step = step || 1; | ||
if (stop < start) { | ||
step = 0 - Math.abs(step); | ||
} | ||
len = Math.max(Math.ceil((stop - start) / step) + 1, 0); | ||
array = new Array(len); | ||
while (i < len) { | ||
array[i++] = start; | ||
start += step; | ||
} | ||
return array; | ||
}; | ||
/** | ||
* Determine if the number is an integer. | ||
* | ||
* @param {Number} the number | ||
* @return {Boolean} true for int, false for not int. | ||
*/ | ||
basic.isInt = function (n) { | ||
return n % 1 === 0; | ||
}; | ||
/** | ||
* Calculate the divisor and modulus of two integers. | ||
* | ||
* @param {Number} int a. | ||
* @param {Number} int b. | ||
* @return {Array} [div, mod]. | ||
*/ | ||
basic.divMod = function (a, b) { | ||
if (!basic.isInt(a) || !basic.isInt(b)) return false; | ||
return [Math.floor(a / b), a % b]; | ||
}; | ||
/** | ||
* Calculate: | ||
* if b >= 1: a^b mod m. | ||
* if b = -1: modInverse(a, m). | ||
* if b < 1: finds a modular rth root of a such that b = 1/r. | ||
* | ||
* @param {Number} Number a. | ||
* @param {Number} Number b. | ||
* @param {Number} Modulo m. | ||
* @return {Number} see the above documentation for return values. | ||
*/ | ||
basic.powerMod = function (a, b, m) { | ||
// If b < -1 should be a small number, this method should work for now. | ||
if (b < -1) return Math.pow(a, b) % m; | ||
if (b === 0) return 1 % m; | ||
if (b >= 1) { | ||
var result = 1; | ||
while (b > 0) { | ||
if ((b % 2) === 1) { | ||
result = (result * a) % m; | ||
} | ||
a = (a * a) % m; | ||
b = b >> 1; | ||
} | ||
return result; | ||
} | ||
if (b === -1) return basic.modInverse(a, m); | ||
if (b < 1) { | ||
return basic.powerMod(a, Math.pow(b, -1), m); | ||
} | ||
}; | ||
/** | ||
* Calculate the extended Euclid Algorithm or extended GCD. | ||
* | ||
* @param {Number} int a. | ||
* @param {Number} int b. | ||
* @return {Array} [a, x, y] a is the GCD. x and y are the values such that ax + by = gcd(a, b) . | ||
*/ | ||
basic.egcd = function (a, b) { | ||
var x = (+b && +a) ? 1 : 0, | ||
y = b ? 0 : 1, | ||
u = (+b && +a) ? 0 : 1, | ||
v = b ? 1 : 0; | ||
b = (+b && +a) ? +b : 0; | ||
a = b ? a : 1; | ||
while (b) { | ||
var dm = basic.divMod(a, b), | ||
q = dm[0], | ||
r = dm[1]; | ||
var m = x - u * q, | ||
n = y - v * q; | ||
a = b; | ||
b = r; | ||
x = u; | ||
y = v; | ||
u = m; | ||
v = n; | ||
} | ||
return [a, x, y]; | ||
}; | ||
/** | ||
* Calculate the modular inverse of a number. | ||
* @param {Number} Number a. | ||
* @param {Number} Modulo m. | ||
* @return {Number} if true, return number, else throw error. | ||
*/ | ||
basic.modInverse = function (a, m) { | ||
var r = basic.egcd(a, m); | ||
if (r[0] != 1) throw new Error('No modular inverse exists'); | ||
return r[1] % m; | ||
}; |
@@ -0,5 +1,24 @@ | ||
/** | ||
* calculus.js | ||
* http://github.com/sjkaliski/numbers.js | ||
* | ||
* Copyright 2012 Stephen Kaliski | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
var numbers = require('../numbers'); | ||
var calculus = exports; | ||
/** | ||
@@ -9,14 +28,13 @@ * Calculate point differential for a specified function at a | ||
* | ||
* @param {Function} math function to be evaluated | ||
* @param {Number} point to be evaluated | ||
* @return {Number} result | ||
* @param {Function} math function to be evaluated. | ||
* @param {Number} point to be evaluated. | ||
* @return {Number} result. | ||
*/ | ||
calculus.pointDiff = function (func, point) { | ||
var a = func(point - 0.00001); | ||
var b = func(point + 0.00001); | ||
var a = func(point - 0.001); | ||
var b = func(point + 0.001); | ||
return (b - a) / (0.00002); | ||
return (b - a) / (0.002); | ||
}; | ||
/** | ||
@@ -26,13 +44,15 @@ * Calculate riemann sum for a specified, one variable, function | ||
* | ||
* @param {Function} math function to be evaluated | ||
* @param {Number} point to initiate evaluation | ||
* @param {Number} point to complete evaluation | ||
* @param {Number} quantity of divisions | ||
* @param {Function} math function to be evaluated. | ||
* @param {Number} point to initiate evaluation. | ||
* @param {Number} point to complete evaluation. | ||
* @param {Number} quantity of divisions. | ||
* @param {Function} (Optional) Function that returns which value | ||
* to sample on each interval; if none is provided, left endpoints | ||
* will be used. | ||
* @return {Number} result | ||
* to sample on each interval; if none is provided, left endpoints | ||
* will be used. | ||
* @return {Number} result. | ||
*/ | ||
calculus.riemann = function (func, start, finish, n, sampler) { | ||
var inc = (finish - start) / n, totalHeight = 0, i; | ||
calculus.Riemann = function (func, start, finish, n, sampler) { | ||
var inc = (finish - start) / n; | ||
var totalHeight = 0; | ||
var i; | ||
@@ -52,3 +72,2 @@ if (typeof sampler === 'function') { | ||
/** | ||
@@ -58,8 +77,8 @@ * Helper function in calculating integral of a function | ||
* | ||
* @param {Function} math function to be evaluated | ||
* @param {Number} point to initiate evaluation | ||
* @param {Number} point to complete evaluation | ||
* @return {Number} evaluation | ||
* @param {Function} math function to be evaluated. | ||
* @param {Number} point to initiate evaluation. | ||
* @param {Number} point to complete evaluation. | ||
* @return {Number} evaluation. | ||
*/ | ||
function simpsonDef (func, a, b) { | ||
function SimpsonDef (func, a, b) { | ||
var c = (a + b) / 2; | ||
@@ -70,3 +89,2 @@ var d = Math.abs(b - a) / 6; | ||
/** | ||
@@ -77,13 +95,13 @@ * Helper function in calculating integral of a function | ||
* | ||
* @param {Function} math function to be evaluated | ||
* @param {Number} point to initiate evaluation | ||
* @param {Number} point to complete evaluation | ||
* @param {Number} total value | ||
* @param {Number} Error bound (epsilon) | ||
* @return {Number} recursive evaluation of left and right side | ||
* @param {Function} math function to be evaluated. | ||
* @param {Number} point to initiate evaluation. | ||
* @param {Number} point to complete evaluation. | ||
* @param {Number} total value. | ||
* @param {Number} Error bound (epsilon). | ||
* @return {Number} recursive evaluation of left and right side. | ||
*/ | ||
function simpsonRecursive (func, a, b, whole, eps) { | ||
var c = a + b, | ||
left = simpsonDef(func, a, c), | ||
right = simpsonDef(func, c, b); | ||
function SimpsonRecursive (func, a, b, whole, eps) { | ||
var c = a + b; | ||
var left = SimpsonDef(func, a, c); | ||
var right = SimpsonDef(func, c, b); | ||
@@ -93,38 +111,36 @@ if (Math.abs(left + right - whole) <= 15 * eps) { | ||
} else { | ||
return simpsonRecursive(func, a, c, eps/2, left) + simpsonRecursive(func, c, b, eps / 2, right); | ||
return SimpsonRecursive(func, a, c, eps / 2, left) + SimpsonRecursive(func, c, b, eps / 2, right); | ||
} | ||
} | ||
/** | ||
* Evaluate area under a curve using adaptive simpson quadrature. | ||
* | ||
* @param {Function} math function to be evaluated | ||
* @param {Number} point to initiate evaluation | ||
* @param {Number} point to complete evaluation | ||
* @param {Function} math function to be evaluated. | ||
* @param {Number} point to initiate evaluation. | ||
* @param {Number} point to complete evaluation. | ||
* @param {Number} Optional error bound (epsilon); | ||
* global error bound will be used as a fallback. | ||
* @return {Number} area underneath curve | ||
* global error bound will be used as a fallback. | ||
* @return {Number} area underneath curve. | ||
*/ | ||
calculus.adaptiveSimpson = function (func, a, b, eps) { | ||
eps = (typeof eps === "undefined") ? numbers.EPSILON : eps; | ||
eps = (typeof eps === 'undefined') ? numbers.EPSILON : eps; | ||
return simpsonRecursive(func, a, b, simpsonDef(func, a, b), eps); | ||
return SimpsonRecursive(func, a, b, SimpsonDef(func, a, b), eps); | ||
}; | ||
/** | ||
* Calculate limit of a function at a given point. Can approach from | ||
* Calculate limit of a function at a given point. Can approach from | ||
* left, middle, or right. | ||
* | ||
* @param {Function} math function to be evaluated | ||
* @param {Number} point to evaluate | ||
* @param {String} approach to limit | ||
* @return {Number} limit | ||
* @param {Function} math function to be evaluated. | ||
* @param {Number} point to evaluate. | ||
* @param {String} approach to limit. | ||
* @return {Number} limit. | ||
*/ | ||
calculus.limit = function (func, point, approach) { | ||
if (approach === 'left') { | ||
return func(point - 0.001); | ||
return func(point - 1e-15); | ||
} else if (approach === 'right') { | ||
return func(point + 0.001); | ||
return func(point + 1e-15); | ||
} else if (approach === 'middle') { | ||
@@ -136,1 +152,41 @@ return (calculus.limit(func, point, 'left') + calculus.limit(func, point, 'right')) / 2; | ||
}; | ||
/** | ||
* Calculate Stirling approximation gamma. | ||
* | ||
* @param {Number} number to calculate. | ||
* @return {Number} gamma. | ||
*/ | ||
calculus.StirlingGamma = function (num) { | ||
return Math.sqrt(2 * Math.PI / num) * Math.pow((num / Math.E), num); | ||
}; | ||
/** | ||
* Calculate Lanczos approximation gamma. | ||
* | ||
* @param {Number} number to calculate. | ||
* @return {Number} gamma. | ||
*/ | ||
calculus.LanczosGamma = function (num) { | ||
var p = [ | ||
0.99999999999980993, 676.5203681218851, -1259.1392167224028, | ||
771.32342877765313, -176.61502916214059, 12.507343278686905, | ||
-0.13857109526572012, 9.9843695780195716e-6, 1.5056327351493116e-7 | ||
]; | ||
var i; | ||
var g = 7; | ||
if(num < 0.5) return Math.PI / (Math.sin(Math.PI * num) * calculus.LanczosGamma(1 - num)); | ||
num -= 1; | ||
var a = p[0]; | ||
var t = num + g + 0.5; | ||
for (i = 1; i < p.length; i++) { | ||
a += p[i] / (num + i); | ||
} | ||
return Math.sqrt(2 * Math.PI) * Math.pow(t, num + 0.5) * Math.exp(-t) * a; | ||
}; |
@@ -0,8 +1,60 @@ | ||
/** | ||
* matrix.js | ||
* http://github.com/sjkaliski/numbers.js | ||
* | ||
* Copyright 2012 Stephen Kaliski | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
var matrix = exports; | ||
/** | ||
* Return a deep copy of the input matrix. | ||
* | ||
* @param {Array} matrix to copy. | ||
* @return {Array} copied matrix. | ||
*/ | ||
matrix.deepCopy = function(arr) { | ||
if (arr[0][0] === undefined) { | ||
throw new Error('Input cannot be a vector.'); | ||
} | ||
var result = new Array(arr.length); | ||
for (var i = 0; i < arr.length; i++) { | ||
result[i] = arr[i].slice(); | ||
} | ||
return result; | ||
}; | ||
/** | ||
* Return true if matrix is square, false otherwise. | ||
* | ||
* @param {Array} arr | ||
*/ | ||
matrix.isSquare = function(arr) { | ||
var rows = arr.length; | ||
var cols = arr[0].length; | ||
return rows === cols; | ||
}; | ||
/** | ||
* Add two matrices together. Matrices must be of same dimension. | ||
* | ||
* @param {Array} matrix A | ||
* @param {Array} matrix B | ||
* @param {Array} matrix A. | ||
* @param {Array} matrix B. | ||
* @return {Array} summed matrix. | ||
@@ -28,9 +80,8 @@ */ | ||
/** | ||
* Scalar multiplication on an matrix. | ||
* | ||
* @param {Array} matrix | ||
* @param {Number} scalar | ||
* @return {Array} updated matrix | ||
* @param {Array} matrix. | ||
* @param {Number} scalar. | ||
* @return {Array} updated matrix. | ||
*/ | ||
@@ -43,10 +94,10 @@ matrix.scalar = function (arr, val) { | ||
} | ||
return arr; | ||
}; | ||
/** | ||
* Transpose a matrix | ||
* Transpose a matrix. | ||
* | ||
* @param {Array} matrix | ||
* @param {Array} matrix. | ||
* @return {Array} transposed matrix. | ||
@@ -60,14 +111,14 @@ */ | ||
for (var j = 0; j < arr.length; j++){ | ||
for (var j = 0; j < arr.length; j++) { | ||
result[i][j] = arr[j][i]; | ||
} | ||
} | ||
return result; | ||
}; | ||
/** | ||
* Create an identity matrix of dimension n x n. | ||
* | ||
* @param {Number} dimension of the identity array to be returned | ||
* @param {Number} dimension of the identity array to be returned. | ||
* @return {Array} n x n identity matrix. | ||
@@ -77,18 +128,19 @@ */ | ||
var result = new Array(n); | ||
for (var i = 0 ; i < n ; i++) { | ||
for (var i = 0; i < n ; i++) { | ||
result[i] = new Array(n); | ||
for (var j = 0 ; j < n ; j++) { | ||
for (var j = 0; j < n; j++) { | ||
result[i][j] = (i === j) ? 1 : 0; | ||
} | ||
} | ||
return result; | ||
}; | ||
/** | ||
* Evaluate dot product of two vectors. Vectors must be of same length. | ||
* | ||
* @param {Array} vector | ||
* @param {Array} vector | ||
* @return {Array} dot product | ||
* @param {Array} vector. | ||
* @param {Array} vector. | ||
* @return {Array} dot product. | ||
*/ | ||
@@ -98,3 +150,3 @@ matrix.dotproduct = function (vectorA, vectorB) { | ||
var result = 0; | ||
for (var i = 0 ; i < vectorA.length ; i++) { | ||
for (var i = 0; i < vectorA.length; i++) { | ||
result += vectorA[i] * vectorB[i]; | ||
@@ -108,3 +160,2 @@ } | ||
/** | ||
@@ -116,5 +167,5 @@ * Multiply two matrices. They must abide by standard matching. | ||
* | ||
* @param {Array} matrix | ||
* @param {Array} matrix | ||
* @return {Array} result of multiplied matrices | ||
* @param {Array} matrix. | ||
* @param {Array} matrix. | ||
* @return {Array} result of multiplied matrices. | ||
*/ | ||
@@ -125,3 +176,3 @@ matrix.multiply = function (arrA, arrB) { | ||
for (var x = 0 ; x < arrA.length ; x++) { | ||
for (var x = 0; x < arrA.length; x++) { | ||
result[x] = new Array(arrB[0].length); | ||
@@ -132,4 +183,4 @@ } | ||
for (var i = 0 ; i < result.length ; i++) { | ||
for (var j = 0 ; j < result[i].length ; j++) { | ||
for (var i = 0; i < result.length; i++) { | ||
for (var j = 0; j < result[i].length; j++) { | ||
result[i][j] = matrix.dotproduct(arrA[i],arrB_T[j]); | ||
@@ -144,23 +195,327 @@ } | ||
/** | ||
* Evaluate determinate of matrix. Matrix must be of dimension | ||
* 2 or 3. | ||
* Evaluate determinate of matrix. Expect speed | ||
* degradation for matrices over 4x4. | ||
* | ||
* @param {Array} matrix | ||
* @return {Number} determinant | ||
* @param {Array} matrix. | ||
* @return {Number} determinant. | ||
*/ | ||
matrix.determinant = function (m) { | ||
if ((m.length === 2) && (m[0].length === 2)) { | ||
var numRow = m.length; | ||
var numCol = m[0].length; | ||
var det = 0; | ||
var row, col; | ||
var diagLeft, diagRight; | ||
if (numRow !== numCol) { | ||
throw new Error("Not a square matrix.") | ||
} | ||
if (numRow === 1) { | ||
return m[0][0]; | ||
} | ||
else if (numRow === 2) { | ||
return m[0][0] * m[1][1] - m[0][1] * m[1][0]; | ||
} else if ((m.length === 3) && (m[0].length === 3)) { | ||
return m[0][0] * m[1][1] * m[2][2] + | ||
m[0][1] * m[1][2] * m[2][0] + | ||
m[0][2] * m[1][0] * m[2][1] - | ||
m[0][2] * m[1][1] * m[2][0] - | ||
m[0][1] * m[1][0] * m[2][2] - | ||
m[0][0] * m[1][2] * m[2][1]; | ||
} | ||
for (col = 0; col < numCol; col++) { | ||
diagLeft = m[0][col]; | ||
diagRight = m[0][col]; | ||
for( row=1; row < numRow; row++ ) { | ||
diagRight *= m[row][(((col + row) % numCol) + numCol) % numCol]; | ||
diagLeft *= m[row][(((col - row) % numCol) + numCol) % numCol]; | ||
} | ||
det += diagRight - diagLeft; | ||
} | ||
return det; | ||
}; | ||
/** | ||
* Returns a LUP decomposition of the given matrix such that: | ||
* | ||
* A*P = L*U | ||
* | ||
* Where | ||
* A is the input matrix | ||
* P is a pivot matrix | ||
* L is a lower triangular matrix | ||
* U is a upper triangular matrix | ||
* | ||
* This method returns an array of three matrices such that: | ||
* | ||
* matrix.luDecomposition(array) = [L, U, P] | ||
* | ||
* @param {Array} arr | ||
* @return {Array} array of matrices [L, U, P] | ||
*/ | ||
matrix.lupDecomposition = function(arr) { | ||
if (!matrix.isSquare(arr)) { | ||
throw new Error("Matrix must be square."); | ||
} | ||
var size = arr.length; | ||
var LU = matrix.deepCopy(arr); | ||
var P = matrix.transpose(matrix.identity(size)); | ||
var currentRow; | ||
var currentColumn = new Array(size); | ||
this.getL = function(a) { | ||
var m = a[0].length; | ||
var L = matrix.identity(m); | ||
for (var i = 0; i < m; i++) { | ||
for (var j = 0; j < m; j++) { | ||
if (i > j) { | ||
L[i][j] = a[i][j]; | ||
} | ||
} | ||
} | ||
return L; | ||
}; | ||
this.getU = function(a) { | ||
var m = a[0].length; | ||
var U = matrix.identity(m); | ||
for (var i = 0; i < m; i++) { | ||
for (var j = 0; j < m; j++) { | ||
if (i <= j) { | ||
U[i][j] = a[i][j]; | ||
} | ||
} | ||
} | ||
return U; | ||
}; | ||
for (var j = 0; j < size; j++) { | ||
var i; | ||
for (i = 0; i < size; i++) { | ||
currentColumn[i] = LU[i][j]; | ||
} | ||
for (i = 0; i < size; i++) { | ||
currentRow = LU[i]; | ||
var minIndex = Math.min(i,j); | ||
var s = 0; | ||
for (var k = 0; k < minIndex; k++) { | ||
s += currentRow[k]*currentColumn[k]; | ||
} | ||
currentRow[j] = currentColumn[i] -= s; | ||
} | ||
//Find pivot | ||
var pivot = j; | ||
for (i = j + 1; i < size; i++) { | ||
if (Math.abs(currentColumn[i]) > Math.abs(currentColumn[pivot])) { | ||
pivot = i; | ||
} | ||
} | ||
if (pivot != j) { | ||
LU = matrix.rowSwitch(LU, pivot, j); | ||
P = matrix.rowSwitch(P, pivot, j); | ||
} | ||
if (j < size && LU[j][j] !== 0) { | ||
for (i = j + 1; i < size; i++) { | ||
LU[i][j] /= LU[j][j]; | ||
} | ||
} | ||
} | ||
return [this.getL(LU), this.getU(LU), P]; | ||
}; | ||
/** | ||
* Rotate a two dimensional vector by degree. | ||
* | ||
* @param {Array} point. | ||
* @param {Number} degree. | ||
* @param {String} direction - clockwise or counterclockwise. | ||
* @return {Array} vector. | ||
*/ | ||
matrix.rotate = function (point, degree, direction) { | ||
if (point.length === 2) { | ||
var negate = direction === 'clockwise' ? -1 : 1; | ||
var radians = degree * (Math.PI / 180); | ||
var transformation = [ | ||
[Math.cos(radians), -1 * negate * Math.sin(radians)], | ||
[negate * Math.sin(radians), Math.cos(radians)] | ||
]; | ||
return matrix.multiply(transformation, point); | ||
} else { | ||
throw new Error('Matrix must be dimension 2 x 2 or 3 x 3'); | ||
throw new Error('Only two dimensional operations are supported at this time'); | ||
} | ||
}; | ||
/** | ||
* Scale a two dimensional vector by scale factor x and scale factor y. | ||
* | ||
* @param {Array} point. | ||
* @param {Number} sx. | ||
* @param {Number} sy. | ||
* @return {Array} vector. | ||
*/ | ||
matrix.scale = function (point, sx, sy) { | ||
if (point.length === 2) { | ||
var transformation = [ | ||
[sx, 0], | ||
[0, sy] | ||
]; | ||
return matrix.multiply(transformation, point); | ||
} else { | ||
throw new Error('Only two dimensional operations are supported at this time'); | ||
} | ||
}; | ||
/** | ||
* Shear a two dimensional vector by shear factor k. | ||
* | ||
* @param {Array} point. | ||
* @param {Number} k. | ||
* @param {String} direction - xaxis or yaxis. | ||
* @return {Array} vector. | ||
*/ | ||
matrix.shear = function (point, k, direction) { | ||
if (point.length === 2) { | ||
var xplaceholder = direction === 'xaxis' ? k : 0; | ||
var yplaceholder = direction === 'yaxis' ? k : 0; | ||
var transformation = [ | ||
[1, xplaceholder], | ||
[yplaceholder, 1] | ||
]; | ||
return matrix.multiply(transformation, point); | ||
} else { | ||
throw new Error('Only two dimensional operations are supported at this time'); | ||
} | ||
}; | ||
/** | ||
* Perform an affine transformation on the given vector. | ||
* | ||
* @param {Array} point. | ||
* @param {Number} tx. | ||
* @param {Number} ty. | ||
* @return {Array} vector. | ||
*/ | ||
matrix.affine = function (point, tx, ty) { | ||
if (point.length === 2) { | ||
var transformation = [ | ||
[1, 0, tx], | ||
[0, 1, ty], | ||
[0, 0, 1 ] | ||
]; | ||
var newpoint = [ | ||
[point[0][0]], | ||
[point[1][0]], | ||
[1] | ||
]; | ||
var transformed = matrix.multiply(transformation, newpoint); | ||
return [ | ||
[transformed[0][0]], | ||
[transformed[1][0]] | ||
]; | ||
} else { | ||
throw new Error('Only two dimensional operations are supported at this time'); | ||
} | ||
}; | ||
/** | ||
* Scales a row of a matrix by a factor and returns the updated matrix. | ||
* Used in row reduction functions. | ||
* | ||
* @param {Array} matrix. | ||
* @param {Number} row. | ||
* @param {Number} scale. | ||
*/ | ||
matrix.rowScale = function (m, row, scale) { | ||
var result = new Array(m.length); | ||
for (var i = 0; i < m.length; i++) { | ||
result[i] = new Array(m[i].length); | ||
for (var j = 0; j < m[i].length; j++) { | ||
if (i === row) { | ||
result[i][j] = scale * m[i][j]; | ||
} else { | ||
result[i][j] = m[i][j]; | ||
} | ||
} | ||
} | ||
return result; | ||
}; | ||
/** | ||
* Swaps two rows of a matrix and returns the updated matrix. | ||
* Used in row reduction functions. | ||
* | ||
* @param {Array} matrix. | ||
* @param {Number} row1. | ||
* @param {Number} row2. | ||
*/ | ||
matrix.rowSwitch = function (m, row1, row2) { | ||
var result = new Array(m.length); | ||
for (var i = 0; i < m.length; i++) { | ||
result[i] = new Array(m[i].length); | ||
for (var j = 0; j < m[i].length; j++) { | ||
if (i === row1) { | ||
result[i][j] = m[row2][j]; | ||
} else if (i === row2) { | ||
result[i][j] = m[row1][j]; | ||
} else { | ||
result[i][j] = m[i][j]; | ||
} | ||
} | ||
} | ||
return result; | ||
}; | ||
/** | ||
* Adds a multiple of one row to another row | ||
* in a matrix and returns the updated matrix. | ||
* Used in row reduction functions. | ||
* | ||
* @param {Array} matrix. | ||
* @param {Number} row1. | ||
* @param {Number} row2. | ||
*/ | ||
matrix.rowAddMultiple = function (m, from, to, scale){ | ||
var result = new Array(m.length); | ||
for (var i = 0; i < m.length; i++) { | ||
result[i] = new Array(m[i].length); | ||
for (var j = 0; j < m[i].length; j++) { | ||
if (i === to) { | ||
result[to][j] = m[to][j] + scale * m[from][j]; | ||
} else { | ||
result[i][j] = m[i][j]; | ||
} | ||
} | ||
} | ||
return result; | ||
}; |
@@ -0,1 +1,21 @@ | ||
/** | ||
* prime.js | ||
* http://github.com/sjkaliski/numbers.js | ||
* | ||
* Copyright 2012 Stephen Kaliski | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
var basic = require('./basic'); | ||
@@ -7,3 +27,3 @@ var prime = exports; | ||
* | ||
* @param {Number} number to evaluate | ||
* @param {Number} number to evaluate. | ||
* @return {Boolean} return true if value is prime. false otherwise. | ||
@@ -15,50 +35,114 @@ */ | ||
else if (val !== undefined) { | ||
var start = 2; | ||
var result = true; | ||
while (start < val) { | ||
var start = 1; | ||
var valSqrt = Math.ceil(Math.sqrt(val)); | ||
while (++start <= valSqrt) { | ||
if (val % start === 0) { | ||
result = false; | ||
break; | ||
} else { | ||
start++; | ||
return false; | ||
} | ||
} | ||
return result; | ||
return true; | ||
} | ||
}; | ||
/** | ||
* Returns the prime factors of a number. | ||
* More info (http://bateru.com/news/2012/05/code-of-the-day-javascript-prime-factors-of-a-number/) | ||
* Taken from Ratio.js | ||
* | ||
* @param {Number} num | ||
* @return {Array} an array of numbers | ||
* @example prime.factorization(20).join(',') === "2,2,5" | ||
**/ | ||
prime.factorization = function (num) { | ||
num = Math.floor(num); | ||
var root; | ||
var factors = []; | ||
var x; | ||
var sqrt = Math.sqrt; | ||
var doLoop = 1 < num && isFinite(num); | ||
while (doLoop) { | ||
root = sqrt(num); | ||
x = 2; | ||
if (num % x) { | ||
x = 3; | ||
while ((num % x) && ((x += 2) < root)) {} | ||
} | ||
x = (root < x) ? num : x; | ||
factors.push(x); | ||
doLoop = (x !== num); | ||
num /= x; | ||
} | ||
// TODO: The maximum call stack size exceeds on this call. Either resolve this | ||
// or abolish the call. | ||
return factors; | ||
}; | ||
/** | ||
* Using trial method, evaluate the prime factorization of a value. | ||
* Determine if a number is prime in Polynomial time, using a randomized algorithm. | ||
* http://en.wikipedia.org/wiki/Miller-Rabin_primality_test | ||
* | ||
* @param {Number} number to evaluate | ||
* @return {Array} array of prime factors for value | ||
* @param {Number} number to Evaluate. | ||
* @param {Number} number to Determine accuracy rate (number of trials) default value = 20. | ||
* @return {Boolean} return true if value is prime. false otherwise. | ||
*/ | ||
// prime.factorization = function (num) { | ||
// if (num === 1) return [1]; | ||
// var primes = [], | ||
// result = []; | ||
// loadPrimes(num, function(p) { | ||
// trial(num); | ||
// }); | ||
prime.millerRabin = function(n, k) { | ||
if (arguments.length === 1) k = 20; | ||
if (n === 2) return true; | ||
if (!basic.isInt(n) || n <= 1 || n % 2 === 0) return false; | ||
// function loadPrimes (n, callback) { | ||
// for (var i = 0 ; i < n ; i++) { | ||
// if (prime.simple(i)) primes.push(i); | ||
// } | ||
var s = 0; | ||
var d = n - 1; | ||
// callback(primes); | ||
// } | ||
while (true) { | ||
var dm = basic.divMod(d, 2); | ||
var quotient = dm[0]; | ||
var remainder = dm[1]; | ||
// function trial (n) { | ||
// var quant = Math.floor(Math.random() * primes.length), | ||
// temp = basic.random(primes, quant); | ||
// if (basic.product(temp) === num) { | ||
// return temp; | ||
// } else { | ||
// trial(n); | ||
// } | ||
// } | ||
// }; | ||
if (remainder === 1) break; | ||
s += 1; | ||
d = quotient; | ||
} | ||
var tryComposite = function (a) { | ||
if (basic.powerMod(a, d, n) === 1) return false; | ||
for (var i = 0; i < s; i ++) { | ||
if (basic.powerMod(a, Math.pow(2, i) * d, n) === n - 1) return false; | ||
} | ||
return true; | ||
} | ||
for (var i = 0; i < k; i++) { | ||
var a = 2 + Math.floor(Math.random() * (n - 2 - 2)); | ||
if (tryComposite(a)) return false; | ||
} | ||
return true; | ||
}; | ||
/** | ||
* Return a list of prime numbers from 1...n, inclusive. | ||
* | ||
* @param {Number} upper limit of test n. | ||
* @return {Array} list of values that are prime up to n. | ||
*/ | ||
prime.sieve = function (n) { | ||
if (n < 2) return []; | ||
var result = [2]; | ||
for (var i = 3; i <= n; i++) { | ||
var notMultiple = false; | ||
for (var j in result) { | ||
notMultiple = notMultiple || (0 === i % result[j]); | ||
} | ||
if (!notMultiple) { | ||
result.push(i); | ||
} | ||
} | ||
return result; | ||
}; |
@@ -0,1 +1,21 @@ | ||
/** | ||
* statistic.js | ||
* http://github.com/sjkaliski/numbers.js | ||
* | ||
* Copyright 2012 Stephen Kaliski | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
var basic = require('./basic'); | ||
@@ -7,76 +27,111 @@ var statistic = exports; | ||
* | ||
* @param {Array} set of values | ||
* @return {Number} mean value | ||
* @param {Array} set of values. | ||
* @return {Number} mean value. | ||
*/ | ||
statistic.mean = function (arr) { | ||
var count = arr.length; | ||
var sum = basic.addition(arr); | ||
var sum = basic.sum(arr); | ||
return sum / count; | ||
}; | ||
/** | ||
* Calculate the median value of a set of numbers in array. | ||
* | ||
* @param {Array} set of values | ||
* @return {Number} median value | ||
* @param {Array} set of values. | ||
* @return {Number} median value. | ||
*/ | ||
statistic.median = function (arr) { | ||
var count = arr.length; | ||
var middle; | ||
if (count % 2 === 0) { | ||
return (arr[count/2] + arr[(count/2 - 1)])/2; | ||
} else { | ||
return arr[Math.floor(count / 2)]; | ||
} | ||
return statistic.quantile(arr, 1, 2); | ||
}; | ||
/** | ||
* Calculate the mode value of a set of numbers in array. | ||
* | ||
* @param {Array} set of values | ||
* @return {Number} mode value | ||
* @param {Array} set of values. | ||
* @return {Number} mode value. | ||
*/ | ||
statistic.mode = function (arr) { | ||
//sort array | ||
var maxIndex = 0, maxOccurence = 0, tempIndex = 0, tempOccurence = 0; | ||
arr = arr.sort(); | ||
while (tempIndex < arr.length) { | ||
for (var j = tempIndex; j < arr.length; j++) { | ||
if (arr[j] == arr[tempIndex]) { | ||
tempOccurence++; | ||
} else { | ||
break; | ||
var counts = {}; | ||
for (var i = 0, n = arr.length; i < n; i++) { | ||
if (counts[arr[i]] === undefined) { | ||
counts[arr[i]] = 0; | ||
} else { | ||
counts[arr[i]]++; | ||
} | ||
} | ||
var highest; | ||
for (var number in counts) { | ||
if (counts.hasOwnProperty(number)) { | ||
if (highest === undefined || counts[number] > counts[highest]) { | ||
highest = number; | ||
} | ||
} | ||
if (tempOccurence > maxOccurence) { | ||
maxOccurence = tempOccurence; | ||
maxIndex = tempIndex; | ||
} | ||
tempIndex = j; | ||
tempOccurence = 0; | ||
} | ||
return arr[maxIndex]; | ||
return Number(highest); | ||
}; | ||
/** | ||
* Calculate the kth q-quantile of a set of numbers in an array. | ||
* As per http://en.wikipedia.org/wiki/Quantile#Quantiles_of_a_population | ||
* Ex: Median is 1st 2-quantile | ||
* Ex: Upper quartile is 3rd 4-quantile | ||
* | ||
* @param {Array} set of values. | ||
* @param {Number} index of quantile. | ||
* @param {Number} number of quantiles. | ||
* @return {Number} kth q-quantile of values. | ||
*/ | ||
statistic.quantile = function (arr, k, q) { | ||
var sorted, count, index; | ||
if (k === 0) return Math.min.apply(null, arr); | ||
if (k === q) return Math.max.apply(null, arr); | ||
sorted = arr.slice(0); | ||
sorted.sort(function (a, b) { return a - b; }); | ||
count = sorted.length; | ||
index = count * k / q; | ||
if (index % 1 === 0) return 0.5 * sorted[index - 1] + 0.5 * sorted[index]; | ||
return sorted[Math.floor(index)]; | ||
}; | ||
/** | ||
* Return a set of summary statistics provided an array. | ||
* | ||
* @return {Object} summary statistics. | ||
*/ | ||
statistic.report = function(array) { | ||
return { | ||
mean: statistic.mean(array), | ||
firstQuartile: statistic.quantile(array, 1, 4), | ||
median: statistic.median(array), | ||
thirdQuartile: statistic.quantile(array, 3, 4), | ||
standardDev: statistic.standardDev(array) | ||
} | ||
}; | ||
/** | ||
* Return a random sample of values over a set of bounds with | ||
* a specified quantity. | ||
* | ||
* @param {Number} lower bound | ||
* @param {Number} upper bound | ||
* @param {Number} quantity of elements in random sample | ||
* @return {Array} random sample | ||
* @param {Number} lower bound. | ||
* @param {Number} upper bound. | ||
* @param {Number} quantity of elements in random sample. | ||
* @return {Array} random sample. | ||
*/ | ||
statistic.randomSample = function (lower, upper, n) { | ||
var sample = []; | ||
var temp = 0; | ||
for (var i = 0 ; i < n ; i++) { | ||
temp = Math.random() * upper; | ||
if (temp > lower) | ||
sample[i] = temp; | ||
while (sample.length < n) { | ||
var temp = Math.random() * upper; | ||
if (lower <= temp <= upper) { | ||
sample.push(temp) | ||
} | ||
} | ||
@@ -87,8 +142,7 @@ | ||
/** | ||
* Evaluate the standard deviation for a set of values. | ||
* | ||
* @param {Array} set of values | ||
* @return {Number} standard deviation | ||
* @param {Array} set of values. | ||
* @return {Number} standard deviation. | ||
*/ | ||
@@ -104,24 +158,128 @@ statistic.standardDev = function (arr) { | ||
return Math.sqrt((1 / count) * basic.addition(squaredArr)); | ||
return Math.sqrt((1 / count) * basic.sum(squaredArr)); | ||
}; | ||
/** | ||
* Evaluate the correlation amongst a set of values. | ||
* | ||
* @param {Array} set of values | ||
* @return {Number} correlation | ||
* @param {Array} set of values. | ||
* @return {Number} correlation. | ||
*/ | ||
statistic.correlation = function (arrX, arrY) { | ||
if (arrX.length == arrY.length) { | ||
var numerator = 0; | ||
var denominator = (arrX.length) * (statistic.standardDev(arrX)) * (statistic.standardDev(arrY)); | ||
var xMean = statistic.mean(arrX); | ||
var yMean = statistic.mean(arrY); | ||
var covarXY = statistic.covariance(arrX, arrY); | ||
var stdDevX = statistic.standardDev(arrX); | ||
var stdDevY = statistic.standardDev(arrY); | ||
for (var i = 0 ; i < arrX.length ; i++) { | ||
numerator += (arrX[i] - xMean) * (arrY[i] - yMean); | ||
return covarXY / (stdDevX * stdDevY); | ||
} else { | ||
throw new Error('Array mismatch'); | ||
} | ||
}; | ||
/** | ||
* Calculate the Coefficient of Determination of a dataset and regression line. | ||
* | ||
* @param {Array} Source data. | ||
* @param {Array} Regression data. | ||
* @return {Number} A number between 0 and 1.0 that represents how well the regression line fits the data. | ||
*/ | ||
statistic.rSquared = function (source, regression) { | ||
var residualSumOfSquares = basic.sum(source.map(function (d,i) { | ||
return basic.square(d - regression[i]); | ||
})); | ||
var totalSumOfSquares = basic.sum(source.map(function (d) { | ||
return basic.square(d - statistic.mean(source)); | ||
})); | ||
return 1 - (residualSumOfSquares / totalSumOfSquares); | ||
}; | ||
/** | ||
* Create a function to calculate the exponential regression of a dataset. | ||
* | ||
* @param {Array} set of values. | ||
* @return {Function} function to accept X values and return corresponding regression Y values. | ||
*/ | ||
statistic.exponentialRegression = function (arrY) { | ||
var n = arrY.length; | ||
var arrX = basic.range(1,n); | ||
var xSum = basic.sum(arrX); | ||
var ySum = basic.sum(arrY); | ||
var yMean = statistic.mean(arrY); | ||
var yLog = arrY.map(function (d) { return Math.log(d); }); | ||
var xSquared = arrX.map(function (d) { return d * d; }); | ||
var xSquaredSum = basic.sum(xSquared); | ||
var yLogSum = basic.sum(yLog); | ||
var xyLog = arrX.map(function (d, i) { return d * yLog[i]; }); | ||
var xyLogSum = basic.sum(xyLog); | ||
var a = (yLogSum * xSquaredSum - xSum * xyLogSum) / (n * xSquaredSum - (xSum * xSum)); | ||
var b = (n * xyLogSum - xSum * yLogSum) / (n * xSquaredSum - (xSum * xSum)); | ||
var fn = function(x) { | ||
if (typeof x === 'number') { | ||
return Math.exp(a) * Math.exp(b * x); | ||
} else { | ||
return x.map(function (d) { | ||
return Math.exp(a) * Math.exp(b * d); | ||
}); | ||
} | ||
}; | ||
return numerator / denominator; | ||
fn.rSquared = statistic.rSquared(arrY, arrX.map(fn)); | ||
return fn; | ||
}; | ||
/** | ||
* Create a function to calculate the linear regression of a dataset. | ||
* | ||
* @param {Array} X array. | ||
* @param {Array} Y array. | ||
* @return {Function} A function which given X or array of X values will return Y. | ||
*/ | ||
statistic.linearRegression = function (arrX, arrY) { | ||
var n = arrX.length; | ||
var xSum = basic.sum(arrX); | ||
var ySum = basic.sum(arrY); | ||
var xySum = basic.sum(arrX.map(function (d, i) { return d * arrY[i]; })); | ||
var xSquaredSum = basic.sum(arrX.map(function (d) { return d * d; })); | ||
var xMean = statistic.mean(arrX); | ||
var yMean = statistic.mean(arrY); | ||
var b = (xySum - 1 / n * xSum * ySum) / (xSquaredSum - 1 / n * (xSum * xSum)); | ||
var a = yMean - b * xMean; | ||
return function(x) { | ||
if (typeof x === 'number') { | ||
return a + b * x; | ||
} else { | ||
return x.map(function (d) { | ||
return a + b * d; | ||
}); | ||
} | ||
} | ||
}; | ||
/** | ||
* Evaluate the covariance amongst 2 sets. | ||
* | ||
* @param {Array} set 1 of values. | ||
* @param {Array} set 2 of values. | ||
* @return {Number} covariance. | ||
*/ | ||
statistic.covariance = function (set1, set2) { | ||
if (set1.length == set2.length) { | ||
var n = set1.length; | ||
var total = 0; | ||
var sum1 = basic.sum(set1); | ||
var sum2 = basic.sum(set2); | ||
for (var i = 0; i < n; i++) { | ||
total += set1[i] * set2[i]; | ||
} | ||
return (total - sum1 * sum2 / n) / n; | ||
} else { | ||
@@ -128,0 +286,0 @@ throw new Error('Array mismatch'); |
@@ -5,3 +5,3 @@ { | ||
"description": "Advanced Mathematics Library for JavaScript", | ||
"version": "0.0.2", | ||
"version": "0.4.0", | ||
"homepage": "https://github.com/sjkaliski/numbers.js", | ||
@@ -26,8 +26,12 @@ "repository": { | ||
], | ||
"dependencies": { | ||
"mocha": "~1.5.0" | ||
"devDependencies": { | ||
"mocha": "~1.5.0", | ||
"browserify": "~1.16.6", | ||
"uglify-js": "~2.2.2", | ||
"jshint": "~0.9.1" | ||
}, | ||
"scripts": { | ||
"test": "make test" | ||
"test": "make test", | ||
"build": "make build" | ||
} | ||
} |
@@ -0,1 +1,2 @@ | ||
# numbers.js [![Build Status](https://travis-ci.org/sjkaliski/numbers.js.png)](https://travis-ci.org/sjkaliski/numbers.js) | ||
Numbers - an advanced mathematics toolkit for JavaScript and Node.js | ||
@@ -32,20 +33,27 @@ developed by Steve Kaliski, [@sjkaliski](http://twitter.com/sjkaliski) | ||
Use riemann integrals (with 200 subdivisions) | ||
```javascript | ||
var numbers = require('numbers'); | ||
var func = function(x) { | ||
return Math.sin(x); | ||
} | ||
numbers.calculus.riemann(func, -2, 4, 200); | ||
numbers.calculus.riemann(Math.sin, -2, 4, 200); | ||
``` | ||
Or adaptive simpson quadrature (with epsilon .0001) | ||
Or use adaptive simpson quadrature (with epsilon .0001) | ||
```javascript | ||
numbers.calculus.adaptiveSimpson(func, -2, 4, .0001); | ||
numbers.calculus.adaptiveSimpson(Math.sin, -2, 4, .0001); | ||
``` | ||
Say we wanted to run some matrix calculations: | ||
User-defined functions can be used too: | ||
``` | ||
var myFunc = function(x) { | ||
return 2*Math.pow(x,2) + 1; | ||
} | ||
numbers.calculus.riemann(myFunc, -2, 4, 200); | ||
numbers.calculus.adaptiveSimpson(myFunc, -2, 4, .0001); | ||
``` | ||
Now say we wanted to run some matrix calculations: | ||
We can add two matrices | ||
@@ -66,3 +74,3 @@ | ||
Numeric.ly also includes some basic prime number analysis. We can check if a number is prime: | ||
Numbers also includes some basic prime number analysis. We can check if a number is prime: | ||
@@ -97,5 +105,33 @@ ```javascript | ||
## Contributors | ||
## Build | ||
To update the public JavaScript, run | ||
``` | ||
make build | ||
``` | ||
This will compile the entire library into a single file accessible at public/numbers.js. It will also minify the file into public/numbers.min.js. | ||
## Core Team | ||
* Steve Kaliski - [@sjkaliski](http://twitter.com/sjkaliski) | ||
* David Byrd - [@davidbyrd11](http://twitter.com/davidbyrd11) | ||
* Ethan Resnick - [@studip101](http://twitter.com/studip101) | ||
* Ethan Resnick - [@studip101](http://twitter.com/studip101) | ||
## Contributors | ||
In no particular order: | ||
* [Ethan aka `altercation`](https://github.com/altercation) | ||
* [Hrishikesh Paranjape aka `hrishikeshparanjape`](https://github.com/hrishikeshparanjape) | ||
* [Greg Leppert aka `leppert`](https://github.com/leppert) | ||
* [Lars-Magnus Skog aka `ralphtheninja`](https://github.com/ralphtheninja) | ||
* [Tim Wood aka `codearachnid`](https://github.com/codearachnid) | ||
* [Miles McCrocklin aka `milroc`](https://github.com/milroc) | ||
* [Nate Kohari aka `nkohari`](https://github.com/nkohari) | ||
* [Eric LaForce aka `elaforc`](https://github.com/elaforc) | ||
* [Kartik Talwar aka `KartikTalwar`](https://github.com/KartikTalwar) | ||
* [btmills aka `btmills`](https://github.com/btmills) | ||
* [swair shah aka `swairshah`](https://github.com/swairshah) | ||
* [Jason Hutchinson aka `Zikes`](https://github.com/Zikes) | ||
* [Philip I. Thomas aka `philipithomas`](https://github.com/philipithomas) | ||
* [Brandon Benvie aka `Benvie`](https://github.com/Benvie) | ||
* [Larry Battle aka `LarryBattle`](https://github.com/LarryBattle) |
@@ -9,23 +9,94 @@ var assert = require('assert'); | ||
// numbers.addition | ||
test('addition should return the sum of items in an array', function (done) { | ||
assert.equal(6, basic.addition([0,1,2,3])); | ||
assert.equal(0, basic.addition([0,-3,5,-2])); | ||
// basic.sum | ||
test('sum should return the sum of items in an array', function (done) { | ||
assert.equal(6, basic.sum([0, 1, 2, 3])); | ||
assert.equal(0, basic.sum([0, -3, 5, -2])); | ||
done(); | ||
}); | ||
// numbers.subtraction | ||
test('sum should throw an exception when given anything but an array', function (done) { | ||
assert.throws( | ||
function() { | ||
basic.sum(1); | ||
}, | ||
/Input must be of type Array/ | ||
); | ||
done(); | ||
}); | ||
test('sum should throw an exception when given anything objects other than numbers', function (done) { | ||
assert.throws( | ||
function() { | ||
basic.sum([1, 2, "error"]); | ||
}, | ||
/All elements in array must be numbers/ | ||
); | ||
done(); | ||
}); | ||
// basic.substraction | ||
test('subtraction should return the difference of items in an array', function (done) { | ||
assert.equal(0, basic.subtraction([0,1,2,3])); | ||
assert.equal(0, basic.subtraction([0, 1, 2, 3])); | ||
done(); | ||
}); | ||
// numbers.product | ||
test('subtraction should throw an exception when given anything but an array', function (done) { | ||
assert.throws( | ||
function() { | ||
basic.subtraction(1); | ||
}, | ||
/Input must be of type Array/ | ||
); | ||
done(); | ||
}); | ||
test('subtraction should throw an exception when given anything objects other than numbers', function (done) { | ||
assert.throws( | ||
function() { | ||
basic.subtraction(["test", 1, 1, 2]); | ||
}, | ||
/All elements in array must be numbers/ | ||
); | ||
done(); | ||
}); | ||
// basic.product | ||
test('product should return the product of items in an array', function (done) { | ||
assert.equal(24, basic.product([1,2,3,4])); | ||
assert.equal(-6, basic.product([-3,2])); | ||
assert.equal(24, basic.product([1, 2, 3, 4])); | ||
assert.equal(-6, basic.product([-3, 2])); | ||
done(); | ||
}); | ||
// numbers.factorial | ||
test('product should throw an exception when given anything but an array', function (done) { | ||
assert.throws( | ||
function() { | ||
basic.product(1); | ||
}, | ||
/Input must be of type Array/ | ||
); | ||
done(); | ||
}); | ||
test('product should throw an exception when given anything objects other than numbers', function (done) { | ||
assert.throws( | ||
function() { | ||
basic.product([1, 2, "error"]); | ||
}, | ||
/All elements in array must be numbers/ | ||
); | ||
done(); | ||
}); | ||
test('square should return the square of a number', function(done) { | ||
assert.equal(16, basic.square(4)); | ||
done(); | ||
}); | ||
// basic.binomial | ||
test('binomial should return the binomial coefficient (n choose k) of two numbers', function(done) { | ||
assert.equal(10, basic.binomial(5, 3)); | ||
done(); | ||
}); | ||
// basic.factorial | ||
test('factorial should return the product of n * (n - 1) * (n - 2) * ... * 1', function (done) { | ||
@@ -37,3 +108,3 @@ assert.equal(24, basic.factorial(4)); | ||
// numbers.gcd | ||
// basic.gcd | ||
test('gcd should return the greatest common denominator of two integers', function (done) { | ||
@@ -45,3 +116,3 @@ assert.equal(6, basic.gcd(1254, 5298)); | ||
// numbers.lcm | ||
// basic.lcm | ||
test('lcm should return the least common multiple of two integers', function (done) { | ||
@@ -51,2 +122,78 @@ assert.equal(240, basic.lcm(12, 80)); | ||
}); | ||
// basic.max | ||
test('max should return the biggest number in an array', function (done) { | ||
assert.equal(42, basic.max([1,2,3,42])); | ||
done(); | ||
}); | ||
// basic.min | ||
test('min should return the smallest number in an array', function (done) { | ||
assert.equal(1, basic.min([2,1,3,42])); | ||
done(); | ||
}); | ||
// basic.range | ||
test('range should return an appropriate range for the given start, stop, and step parameters', function (done) { | ||
assert.deepEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10],basic.range(1, 10)); | ||
assert.deepEqual([10, 9, 8, 7, 6, 5, 4, 3, 2, 1],basic.range(10, 1)); | ||
assert.deepEqual([1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5],basic.range(1, 5, 0.5)); | ||
assert.deepEqual([5, 4.5, 4, 3.5, 3, 2.5, 2, 1.5, 1],basic.range(5, 1, 0.5)); | ||
done(); | ||
}); | ||
// basic.isInt | ||
test('isInt checks for an integer', function (done) { | ||
assert.equal(false, basic.isInt(2.32)); | ||
assert.equal(false, basic.isInt("true")); | ||
assert.equal(true, basic.isInt("2")); //based off impelementation change | ||
assert.equal(true, basic.isInt(2)); | ||
done(); | ||
}); | ||
// basic.divMod | ||
test('divMod should return an array of both the division and modulus values of two integers', function (done) { | ||
assert.deepEqual([2, 0], basic.divMod(12, 6)); | ||
assert.deepEqual([3, 1], basic.divMod(10, 3)); | ||
done(); | ||
}); | ||
// basic.egcd | ||
test('egcd should return the array [a, x, y] which is the solved linear equation for GCD', function(done) { | ||
assert.deepEqual([5, -3, 5], basic.egcd(65, 40)); | ||
assert.deepEqual([5, 5, -3], basic.egcd(40, 65)); | ||
assert.deepEqual([21, -16, 27], basic.egcd(1239, 735)); | ||
assert.deepEqual([21, 5, -2], basic.egcd(105, 252)); | ||
assert.deepEqual([21, -2, 5], basic.egcd(252, 105)); | ||
done(); | ||
}); | ||
// basic.modInverse | ||
test('modInverse will return the modulo m inverse of a', function(done) { | ||
assert.equal(1, basic.modInverse(1, 5)); | ||
done(); | ||
}); | ||
test('modInverse will throw an exception if no modular inverse exists', function(done) { | ||
assert.throws( | ||
function() { | ||
basic.modInverse(65, 40); | ||
}, | ||
/No modular inverse exists/ | ||
); | ||
done(); | ||
}); | ||
// basic.powerMod | ||
test('powerMod should return the answer to a^b mod m', function (done) { | ||
assert.equal(1, basic.powerMod(1, -1, 5)); | ||
assert.equal(1, basic.powerMod(2, 10, 3)); | ||
assert.equal(16, basic.powerMod(2, Math.pow(10, 9), 18)); | ||
assert.equal(6, basic.powerMod(6, 0.5, 10)); | ||
assert.equal(445, basic.powerMod(4, 13, 497)); | ||
done(); | ||
}); | ||
}); | ||
@@ -10,3 +10,3 @@ var assert = require('assert'); | ||
test('pointDiff should return the derivative at a point, provided function', function(done) { | ||
var func = function(x) { | ||
var func = function (x) { | ||
return 2 * x + 2; | ||
@@ -22,7 +22,7 @@ }; | ||
test('riemann should return an estimated definite integral of a function', function(done) { | ||
var func = function(x) { | ||
var func = function (x) { | ||
return 2 * Math.pow(x, 2); | ||
}; | ||
var res = calculus.riemann(func, 0, 100, 10); | ||
var res = calculus.Riemann(func, 0, 100, 10); | ||
@@ -34,3 +34,3 @@ assert.equal(570000, res); | ||
test('adaptive simpson should return an estimated definite integral of a function', function(done) { | ||
var func = function(x) { | ||
var func = function (x) { | ||
return 2 * Math.pow(x, 2); | ||
@@ -46,3 +46,3 @@ }; | ||
test('limit should return the limit of a function at a given point from left, middle, or right', function(done) { | ||
var func = function(x) { | ||
var func = function (x) { | ||
return Math.pow(x, 2) * Math.sin(2 * x); | ||
@@ -57,2 +57,17 @@ }; | ||
}); | ||
test('Stirling approximation gamma should return correct values', function (done) { | ||
assert.equal(true, numbers.EPSILON > 5.69718714897717 - calculus.StirlingGamma(0.1)); | ||
assert.equal(true, numbers.EPSILON > 3.3259984240223925 - calculus.StirlingGamma(0.2)); | ||
assert.equal(true, numbers.EPSILON > 2.3625300362696198 - calculus.StirlingGamma(0.3)); | ||
assert.equal(true, numbers.EPSILON > 0.8426782594483921 - calculus.StirlingGamma(1.3)); | ||
done(); | ||
}); | ||
test('Lanczos approximation gamma should return correct values', function (done) { | ||
assert.equal(true, numbers.EPSILON > 9.513507698668736 - calculus.LanczosGamma(0.1)); | ||
assert.equal(true, numbers.EPSILON > 4.590843711998803 - calculus.LanczosGamma(0.2)); | ||
assert.equal(true, numbers.EPSILON > 2.9915689876875904 - calculus.LanczosGamma(0.3)); | ||
assert.equal(true, numbers.EPSILON > 0.8974706963062777 - calculus.LanczosGamma(1.3)); | ||
done(); | ||
}); | ||
}); |
@@ -9,2 +9,26 @@ var assert = require('assert'); | ||
test('should create a deep copy of a matrix', function(done) { | ||
var input = [[1,2],[2,1]]; | ||
var copy = matrix.deepCopy(input); | ||
assert.notEqual(input, copy); | ||
assert.throws( | ||
function() { | ||
matrix.deepCopy([1,2]) | ||
}, | ||
/Input cannot be a vector./ | ||
); | ||
done(); | ||
}); | ||
test('should be able to tell if a matrix is square', function(done) { | ||
assert.equal(matrix.isSquare([[1,2],[3,4]]), true); | ||
assert.equal(matrix.isSquare([[1,2,3],[4,5,6]]), false); | ||
done(); | ||
}); | ||
test('should return sum of two matrices', function(done) { | ||
@@ -102,3 +126,28 @@ var arrA = [ | ||
test('should return product of matrix and a vector', function(done) { | ||
var matrixA = [ | ||
[0, 1, 2], | ||
[3, 4, 5] | ||
]; | ||
var matrixB = [ | ||
[0], | ||
[1], | ||
[2] | ||
]; | ||
var res = matrix.multiply(matrixA, matrixB); | ||
assert.deepEqual([[5], [14]], res); | ||
done(); | ||
}); | ||
test('should return determinant of matrix', function(done) { | ||
var m0 = [ | ||
[1] | ||
]; | ||
var res0 = matrix.determinant(m0); | ||
assert.equal(1, res0); | ||
var m1 = [ | ||
@@ -123,3 +172,240 @@ [2, 3], | ||
}); | ||
test('should throw an error for calculating the determinant of a non-square matrix', function(done) { | ||
var m3 = [ | ||
[3, -7, 8, 9, -6], | ||
[0, 2, -5, 7, 3], | ||
[0, 0, 1, 5, 0], | ||
[0, 0, 0, -2, 0] | ||
]; | ||
assert.throws(function() { | ||
matrix.determinant(m3); | ||
}, | ||
/Not a square matrix/ | ||
); | ||
done(); | ||
}); | ||
test('should throw an error if trying to get LU decomposition of non-square matrix', function(done) { | ||
assert.throws( | ||
function() { | ||
matrix.lupDecomposition([[1,2,3],[4,5,6]]); | ||
}, | ||
/Matrix must be square./ | ||
); | ||
done(); | ||
}); | ||
test('should return the LU decomposition of a matrix', function(done) { | ||
var inputMatrix = [[1, 0, 0, 2], [2, -2, 0, 5], [1, -2, -2, 3], [5, -3, -5, 2]]; | ||
var firstLup = matrix.lupDecomposition(inputMatrix); | ||
assert.deepEqual(matrix.multiply(firstLup[0], firstLup[1]), | ||
matrix.multiply(firstLup[2], inputMatrix)); | ||
var secondInputMatrix = [[1, 0, 0, 2], [1, -2, 0, 5], [1, -2, 0, 3], [1, -3, -5, 0]]; | ||
var secondLup = matrix.lupDecomposition(secondInputMatrix); | ||
assert.deepEqual(matrix.multiply(secondLup[0], secondLup[1]), | ||
matrix.multiply(secondLup[2], secondInputMatrix)); | ||
done(); | ||
}); | ||
test('should return a new vector that has been rotated by the transformation matrix', function(done) { | ||
var vectorA = [[0], [1]]; | ||
var degree = 90; | ||
var res = matrix.rotate(vectorA, degree, 'clockwise'); | ||
assert.equal((res[0][0] > (1 - numbers.EPSILON)), true); | ||
assert.equal((res[0][0] < (1 + numbers.EPSILON)), true); | ||
assert.equal((res[1][0] > (0 - numbers.EPSILON)), true); | ||
assert.equal((res[1][0] < (0 + numbers.EPSILON)), true); | ||
done(); | ||
}); | ||
test('should throw an error if a vector larger than two is given for rotation', function(done) { | ||
var vectorA = [[0], [1], [2]]; | ||
var degree = 90; | ||
assert.throws( | ||
function() { | ||
matrix.rotate(vectorA, degree, 'clockwise'); | ||
}, | ||
/Only two dimensional operations are supported at this time/ | ||
); | ||
done(); | ||
}); | ||
test('should return a new vector that has been scaled by the transformation matrix', function(done) { | ||
var vectorA = [[2], [5]]; | ||
var sx = 10; | ||
var sy = 5; | ||
var expected = [ [20], [25] ]; | ||
var res = matrix.scale(vectorA, sx, sy); | ||
assert.deepEqual(expected, res); | ||
done(); | ||
}); | ||
test('should throw an error if a vector larger than two is given for scaling', function(done) { | ||
var vectorA = [[0], [1], [2]]; | ||
var sx = 10; | ||
var sy = 5; | ||
assert.throws( | ||
function() { | ||
var res = matrix.scale(vectorA, sx, sy); | ||
}, | ||
/Only two dimensional operations are supported at this time/ | ||
); | ||
done(); | ||
}); | ||
test('should return a new vector that has been sheared in the x direction by the transformation matrix', function(done) { | ||
var vectorA = [[2], [5]]; | ||
var k = 10; | ||
var direction = "xaxis" | ||
var expected = [ [52], [5] ]; | ||
var res = matrix.shear(vectorA, k, direction); | ||
assert.deepEqual(expected, res); | ||
done(); | ||
}); | ||
test('should return a new vector that has been sheared in the y direction by the transformation matrix', function(done) { | ||
var vectorA = [[2], [5]]; | ||
var k = 10; | ||
var direction = "yaxis" | ||
var expected = [ [2], [25] ]; | ||
var res = matrix.shear(vectorA, k, direction); | ||
assert.deepEqual(expected, res); | ||
done(); | ||
}); | ||
test('should throw an error if a vector larger than two is given for shearing', function(done) { | ||
var vectorA = [[0], [1], [2]]; | ||
var k = 10; | ||
var direction = "yaxis" | ||
assert.throws( | ||
function() { | ||
var res = matrix.shear(vectorA, k, direction); | ||
}, | ||
/Only two dimensional operations are supported at this time/ | ||
); | ||
done(); | ||
}); | ||
test('should return a new vector that has been transformed by the affine transformation matrix', function(done) { | ||
var vectorA = [[2], [5]]; | ||
var tx = 10; | ||
var ty = 10; | ||
var expected = [ [12], [15] ]; | ||
var res = matrix.affine(vectorA, tx, ty); | ||
assert.deepEqual(expected, res); | ||
done(); | ||
}); | ||
test('should throw an error if a vector larger than two is given for the affine transform', function(done) { | ||
var vectorA = [[0], [1], [2]]; | ||
var tx = 10; | ||
var ty = 10; | ||
assert.throws( | ||
function() { | ||
var res = matrix.affine(vectorA, tx, ty); | ||
}, | ||
/Only two dimensional operations are supported at this time/ | ||
); | ||
done(); | ||
}); | ||
test('should return a new matrix that has a scaled row for the rowScale function', function(done) { | ||
var m = [ | ||
[0, 1, 2], | ||
[3, -1, 5], | ||
[1, 2, 5] | ||
]; | ||
var expected1 = [ | ||
[0, 0, 0], | ||
[3, -1, 5], | ||
[1, 2, 5] | ||
]; | ||
var res1 = matrix.rowScale(m,0,0); | ||
assert.deepEqual(res1,expected1); | ||
var expected2 = [ | ||
[0, 1, 2], | ||
[-6, 2, -10], | ||
[1, 2, 5] | ||
]; | ||
var res2 = matrix.rowScale( m , 1 , -2 ); | ||
assert.deepEqual( res2 , expected2 ); | ||
done(); | ||
}); | ||
test('should return a new matrix that has rows changed with the rowSwitch function', function(done) { | ||
var m = [ | ||
[0, 1, 2], | ||
[3, -1, 5], | ||
[1, 2, 5] | ||
]; | ||
var expected1 = [ | ||
[3, -1, 5], | ||
[0, 1, 2], | ||
[1, 2, 5] | ||
]; | ||
var res1 = matrix.rowSwitch(m,0,1); | ||
assert.deepEqual(res1,expected1); | ||
var res2 = matrix.rowScale(m,1,1); | ||
assert.deepEqual(res2,m); | ||
done(); | ||
}); | ||
test('should return a new matrix that has a multiple of one row added to another using the rowAddMultiple function', function(done) { | ||
var m = [ | ||
[0, 1, 2], | ||
[3, -1, 5], | ||
[1, 2, 5] | ||
]; | ||
var expected1 = [ | ||
[0, 1, 2], | ||
[3, 1, 9], | ||
[1, 2, 5] | ||
]; | ||
var res1 = matrix.rowAddMultiple(m,0,1,2); | ||
assert.deepEqual(res1,expected1); | ||
var res2 = matrix.rowScale(m,1,1,0); | ||
assert.deepEqual(res2,m); | ||
done(); | ||
}); | ||
}); |
@@ -6,12 +6,67 @@ var assert = require('assert'); | ||
suite('numbers', function() { | ||
var primes = [2, 17, 839, 3733, 999983]; | ||
var composites = [1, 4, 18, 25, 838, 3007]; | ||
console.log('\n\n\033[34mTesting Prime Number Mathematics\033[0m'); | ||
// prime.simple | ||
test('simple should be able to determine if a number is prime or not', function(done) { | ||
for (var i = 0; i < primes.length; i++) { | ||
assert.equal(true, prime.simple(primes[i]), primes[i] + " should be prime"); | ||
} | ||
for (i = 0; i < composites.length; i++) { | ||
assert.equal(false, prime.simple(composites[i]), composites[i] + " should not be prime"); | ||
} | ||
done(); | ||
}); | ||
// prime.millerRabin | ||
test('millerRabin should be able to determine if a number is prime or not', function(done) { | ||
for (var i = 0; i < primes.length; i++) { | ||
assert.equal(true, prime.millerRabin(primes[i]), primes[i] + " should be prime"); | ||
} | ||
for (i = 0; i < composites.length; i++) { | ||
assert.equal(false, prime.millerRabin(composites[i]), composites[i] + " should not be prime"); | ||
} | ||
done(); | ||
}); | ||
// prime.sieve | ||
test('should be able to determine if a number is prime or not', function(done) { | ||
assert.equal(false, prime.simple(1)); | ||
assert.equal(true, prime.simple(2)); | ||
assert.equal(true, prime.simple(17)); | ||
done() | ||
assert.deepEqual([], prime.sieve(1)); | ||
assert.deepEqual([2], prime.sieve(2)); | ||
assert.deepEqual([2, 3, 5, 7, 11, 13, 17], prime.sieve(17)); | ||
done(); | ||
}); | ||
//prime.factorization when values < 2 | ||
test("factorization should return an empty array for values < 2, infinite or not numeric", function (done) { | ||
var func = prime.factorization; | ||
assert.deepEqual(func(Infinity), []); | ||
assert.deepEqual(func({}), []); | ||
assert.deepEqual(func(null), []); | ||
assert.deepEqual(func(-1), []); | ||
assert.deepEqual(func(0), []); | ||
assert.deepEqual(func(1), []); | ||
done(); | ||
}); | ||
//prime.factorization when 1 < values < infinity | ||
test("factorization should return the prime factors for x where 1 < x < infinity", function (done) { | ||
var func = prime.factorization; | ||
assert.deepEqual(func(2), [2]); | ||
assert.deepEqual(func(6), [2, 3]); | ||
assert.deepEqual(func(9), [3, 3]); | ||
assert.deepEqual(func("729"), [3, 3, 3, 3, 3, 3]); | ||
assert.deepEqual(func(3333333791), [2347, 1420253]); | ||
assert.deepEqual(func(123456789), [3, 3, 3607, 3803]); | ||
assert.deepEqual(func(9876543210), [2, 3, 3, 5, 17, 17, 379721]); | ||
assert.deepEqual(func("103103103"), [3, 103, 333667]); | ||
done(); | ||
}); | ||
}); |
var assert = require('assert'); | ||
var numbers = require('../index.js'); | ||
var statistic = numbers.statistic; | ||
var basic = numbers.basic; | ||
@@ -11,13 +12,27 @@ suite('numbers', function() { | ||
var res = statistic.mean([0, 1, 2]); | ||
assert.equal(1, res); | ||
assert.equal(1, res); | ||
done(); | ||
}); | ||
test('median should return middle value in array', function(done) { | ||
var res1 = statistic.median([0, 1, 2]); | ||
test('median should return middle value in array for a sorted array with an odd number of values', function(done) { | ||
var res1 = statistic.median([0, 2, 15]); | ||
assert.equal(2, res1); | ||
done(); | ||
}); | ||
test('median should return middle value in array for an unsorted array with an odd number of values', function(done) { | ||
var res1 = statistic.median([1, 0, 2]); | ||
assert.equal(1, res1); | ||
done(); | ||
}); | ||
test('median should return average of two middle values in array for a sorted array with an even number of values', function(done) { | ||
var res2 = statistic.median([0, 1, 2, 3]); | ||
assert.equal(1.5, res2); | ||
done(); | ||
}); | ||
test('median should return average of two middle values in array for an unsorted array with an even number of values', function(done) { | ||
var res2 = statistic.median([1, 3, 2, 0]); | ||
assert.equal(1.5, res2); | ||
done(); | ||
@@ -32,2 +47,28 @@ }); | ||
test('quantile should return lowest value in array for 0th q-quantile of an unsorted array', function(done) { | ||
var arr = [5, 2, 4]; | ||
var res = statistic.quantile(arr, 0, 1); | ||
assert.equal(2, res); | ||
done(); | ||
}); | ||
test('quantile should return highest value in array for qth q-quantile of an unsorted array', function(done) { | ||
var arr = [5, 2, 4]; | ||
var res = statistic.quantile(arr, 6, 6); | ||
assert.equal(5, res); | ||
done(); | ||
}); | ||
test('quantile should return average of two values in array for an unsorted array\'s length is a multiple of (k / q)', function(done) { | ||
var res = statistic.quantile([9, 1, 1, 9], 2, 4); | ||
assert.equal(5, res); | ||
done(); | ||
}); | ||
test('quantile should return value at 0-based index floor(k/q) in array for an unsorted array\'s length is not a multiple of (k/q)', function(done) { | ||
var res = statistic.quantile([3, 6, 7, 8, 8, 9, 10, 13, 15, 16, 20], 1, 4); | ||
assert.equal(7, res); | ||
done(); | ||
}); | ||
test('randomSample should return an array of random numbers in a certain bound', function(done) { | ||
@@ -56,6 +97,55 @@ var res = statistic.randomSample(5, 100, 5); | ||
assert.equal(0.43413125731182345, res); | ||
assert.equal(0.43413125731182334, res); | ||
done(); | ||
}); | ||
test('should return a function to calculate the linear regression of a set of points', function (done) { | ||
var arrX = [1,2,3,4,5,7,8,9]; | ||
var arrY = [1,2,3,4,5,7,7,9]; | ||
var regression_function = statistic.linearRegression(arrX,arrY); | ||
assert.equal(19.07218683651805, regression_function(20)); | ||
done(); | ||
}); | ||
test('should return a function to calculate the exponential regression of an array of numbers', function (done) { | ||
var input = [10,9,8,8,7,7,6,6.5,6.4,6.3,6.2]; | ||
var output = [ | ||
9.077131929916444, 8.66937771538526, 8.279940244595563, 7.907996710352883, | ||
7.552761266818376, 7.213483369166244, 6.8894461878255076, 6.579965093955639, | ||
6.284386212956255, 6.002085042954625, 5.732465135352174 | ||
]; | ||
var regression_function = statistic.exponentialRegression(input); | ||
assert.equal(0.8491729985314136, regression_function.rSquared); | ||
assert.deepEqual(output, regression_function(basic.range(1, input.length))); | ||
assert.equal(9.077131929916444, regression_function(1)); | ||
assert.equal(4.769782016165231, regression_function(15)); | ||
done(); | ||
}); | ||
test('should return an appropriate Coefficient of Determination for a given dataset and regression', function (done) { | ||
var input = [10,9,8,8,7,7,6,6.5,6.4,6.3,6.2]; | ||
var output = [ | ||
9.077131929916444, 8.66937771538526, 8.279940244595563, 7.907996710352883, | ||
7.552761266818376, 7.213483369166244, 6.8894461878255076, 6.579965093955639, | ||
6.284386212956255, 6.002085042954625, 5.732465135352174 | ||
]; | ||
assert.equal(0.8491729985314136, statistic.rSquared(input, output)); | ||
done(); | ||
}); | ||
test('should return covariance between two arrays', function(done) { | ||
var arr1 = [-5, -4, -1, 0, 5, 100]; | ||
var arr2 = [-6, 5, 2, 5, 2, 6]; | ||
var res = statistic.covariance(arr1, arr2); | ||
assert.equal(66.05555555555556, res); | ||
done(); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Debug access
Supply chain riskUses debug, reflection and dynamic code execution features.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
176009
0
30
4344
135
4
2
16
1
- Removedmocha@~1.5.0
- Removedcommander@0.6.1(transitive)
- Removeddebug@4.4.0(transitive)
- Removeddiff@1.0.2(transitive)
- Removedgrowl@1.5.1(transitive)
- Removedjade@0.26.3(transitive)
- Removedmkdirp@0.3.00.3.3(transitive)
- Removedmocha@1.5.0(transitive)
- Removedms@0.3.02.1.3(transitive)