971 lines
25 KiB
JavaScript
971 lines
25 KiB
JavaScript
/* Provides functions for the solution of linear system of equations, integration, extrapolation,
|
|
* interpolation, eigenvalue problems, differential equations and PCA analysis. */
|
|
|
|
(function(jStat, Math) {
|
|
|
|
var push = Array.prototype.push;
|
|
var isArray = jStat.utils.isArray;
|
|
|
|
function isUsable(arg) {
|
|
return isArray(arg) || arg instanceof jStat;
|
|
}
|
|
|
|
jStat.extend({
|
|
|
|
// add a vector/matrix to a vector/matrix or scalar
|
|
add: function add(arr, arg) {
|
|
// check if arg is a vector or scalar
|
|
if (isUsable(arg)) {
|
|
if (!isUsable(arg[0])) arg = [ arg ];
|
|
return jStat.map(arr, function(value, row, col) {
|
|
return value + arg[row][col];
|
|
});
|
|
}
|
|
return jStat.map(arr, function(value) { return value + arg; });
|
|
},
|
|
|
|
// subtract a vector or scalar from the vector
|
|
subtract: function subtract(arr, arg) {
|
|
// check if arg is a vector or scalar
|
|
if (isUsable(arg)) {
|
|
if (!isUsable(arg[0])) arg = [ arg ];
|
|
return jStat.map(arr, function(value, row, col) {
|
|
return value - arg[row][col] || 0;
|
|
});
|
|
}
|
|
return jStat.map(arr, function(value) { return value - arg; });
|
|
},
|
|
|
|
// matrix division
|
|
divide: function divide(arr, arg) {
|
|
if (isUsable(arg)) {
|
|
if (!isUsable(arg[0])) arg = [ arg ];
|
|
return jStat.multiply(arr, jStat.inv(arg));
|
|
}
|
|
return jStat.map(arr, function(value) { return value / arg; });
|
|
},
|
|
|
|
// matrix multiplication
|
|
multiply: function multiply(arr, arg) {
|
|
var row, col, nrescols, sum, nrow, ncol, res, rescols;
|
|
// eg: arr = 2 arg = 3 -> 6 for res[0][0] statement closure
|
|
if (arr.length === undefined && arg.length === undefined) {
|
|
return arr * arg;
|
|
}
|
|
nrow = arr.length,
|
|
ncol = arr[0].length,
|
|
res = jStat.zeros(nrow, nrescols = (isUsable(arg)) ? arg[0].length : ncol),
|
|
rescols = 0;
|
|
if (isUsable(arg)) {
|
|
for (; rescols < nrescols; rescols++) {
|
|
for (row = 0; row < nrow; row++) {
|
|
sum = 0;
|
|
for (col = 0; col < ncol; col++)
|
|
sum += arr[row][col] * arg[col][rescols];
|
|
res[row][rescols] = sum;
|
|
}
|
|
}
|
|
return (nrow === 1 && rescols === 1) ? res[0][0] : res;
|
|
}
|
|
return jStat.map(arr, function(value) { return value * arg; });
|
|
},
|
|
|
|
// outer([1,2,3],[4,5,6])
|
|
// ===
|
|
// [[1],[2],[3]] times [[4,5,6]]
|
|
// ->
|
|
// [[4,5,6],[8,10,12],[12,15,18]]
|
|
outer:function outer(A, B) {
|
|
return jStat.multiply(A.map(function(t){ return [t] }), [B]);
|
|
},
|
|
|
|
|
|
// Returns the dot product of two matricies
|
|
dot: function dot(arr, arg) {
|
|
if (!isUsable(arr[0])) arr = [ arr ];
|
|
if (!isUsable(arg[0])) arg = [ arg ];
|
|
// convert column to row vector
|
|
var left = (arr[0].length === 1 && arr.length !== 1) ? jStat.transpose(arr) : arr,
|
|
right = (arg[0].length === 1 && arg.length !== 1) ? jStat.transpose(arg) : arg,
|
|
res = [],
|
|
row = 0,
|
|
nrow = left.length,
|
|
ncol = left[0].length,
|
|
sum, col;
|
|
for (; row < nrow; row++) {
|
|
res[row] = [];
|
|
sum = 0;
|
|
for (col = 0; col < ncol; col++)
|
|
sum += left[row][col] * right[row][col];
|
|
res[row] = sum;
|
|
}
|
|
return (res.length === 1) ? res[0] : res;
|
|
},
|
|
|
|
// raise every element by a scalar
|
|
pow: function pow(arr, arg) {
|
|
return jStat.map(arr, function(value) { return Math.pow(value, arg); });
|
|
},
|
|
|
|
// exponentiate every element
|
|
exp: function exp(arr) {
|
|
return jStat.map(arr, function(value) { return Math.exp(value); });
|
|
},
|
|
|
|
// generate the natural log of every element
|
|
log: function exp(arr) {
|
|
return jStat.map(arr, function(value) { return Math.log(value); });
|
|
},
|
|
|
|
// generate the absolute values of the vector
|
|
abs: function abs(arr) {
|
|
return jStat.map(arr, function(value) { return Math.abs(value); });
|
|
},
|
|
|
|
// computes the p-norm of the vector
|
|
// In the case that a matrix is passed, uses the first row as the vector
|
|
norm: function norm(arr, p) {
|
|
var nnorm = 0,
|
|
i = 0;
|
|
// check the p-value of the norm, and set for most common case
|
|
if (isNaN(p)) p = 2;
|
|
// check if multi-dimensional array, and make vector correction
|
|
if (isUsable(arr[0])) arr = arr[0];
|
|
// vector norm
|
|
for (; i < arr.length; i++) {
|
|
nnorm += Math.pow(Math.abs(arr[i]), p);
|
|
}
|
|
return Math.pow(nnorm, 1 / p);
|
|
},
|
|
|
|
// computes the angle between two vectors in rads
|
|
// In case a matrix is passed, this uses the first row as the vector
|
|
angle: function angle(arr, arg) {
|
|
return Math.acos(jStat.dot(arr, arg) / (jStat.norm(arr) * jStat.norm(arg)));
|
|
},
|
|
|
|
// augment one matrix by another
|
|
// Note: this function returns a matrix, not a jStat object
|
|
aug: function aug(a, b) {
|
|
var newarr = [];
|
|
var i;
|
|
for (i = 0; i < a.length; i++) {
|
|
newarr.push(a[i].slice());
|
|
}
|
|
for (i = 0; i < newarr.length; i++) {
|
|
push.apply(newarr[i], b[i]);
|
|
}
|
|
return newarr;
|
|
},
|
|
|
|
// The inv() function calculates the inverse of a matrix
|
|
// Create the inverse by augmenting the matrix by the identity matrix of the
|
|
// appropriate size, and then use G-J elimination on the augmented matrix.
|
|
inv: function inv(a) {
|
|
var rows = a.length;
|
|
var cols = a[0].length;
|
|
var b = jStat.identity(rows, cols);
|
|
var c = jStat.gauss_jordan(a, b);
|
|
var result = [];
|
|
var i = 0;
|
|
var j;
|
|
|
|
//We need to copy the inverse portion to a new matrix to rid G-J artifacts
|
|
for (; i < rows; i++) {
|
|
result[i] = [];
|
|
for (j = cols; j < c[0].length; j++)
|
|
result[i][j - cols] = c[i][j];
|
|
}
|
|
return result;
|
|
},
|
|
|
|
// calculate the determinant of a matrix
|
|
det: function det(a) {
|
|
if (a.length === 2) {
|
|
return a[0][0] * a[1][1] - a[0][1] * a[1][0];
|
|
}
|
|
|
|
var determinant = 0;
|
|
for (var i = 0; i < a.length; i++) {
|
|
// build a sub matrix without column `i`
|
|
var submatrix = [];
|
|
for (var row = 1; row < a.length; row++) {
|
|
submatrix[row - 1] = [];
|
|
for (var col = 0; col < a.length; col++) {
|
|
if (col < i) {
|
|
submatrix[row - 1][col] = a[row][col];
|
|
} else if (col > i) {
|
|
submatrix[row - 1][col - 1] = a[row][col];
|
|
}
|
|
}
|
|
}
|
|
|
|
// alternate between + and - between determinants
|
|
var sign = i % 2 ? -1 : 1;
|
|
determinant += det(submatrix) * a[0][i] * sign;
|
|
}
|
|
|
|
return determinant
|
|
},
|
|
|
|
gauss_elimination: function gauss_elimination(a, b) {
|
|
var i = 0,
|
|
j = 0,
|
|
n = a.length,
|
|
m = a[0].length,
|
|
factor = 1,
|
|
sum = 0,
|
|
x = [],
|
|
maug, pivot, temp, k;
|
|
a = jStat.aug(a, b);
|
|
maug = a[0].length;
|
|
for(i = 0; i < n; i++) {
|
|
pivot = a[i][i];
|
|
j = i;
|
|
for (k = i + 1; k < m; k++) {
|
|
if (pivot < Math.abs(a[k][i])) {
|
|
pivot = a[k][i];
|
|
j = k;
|
|
}
|
|
}
|
|
if (j != i) {
|
|
for(k = 0; k < maug; k++) {
|
|
temp = a[i][k];
|
|
a[i][k] = a[j][k];
|
|
a[j][k] = temp;
|
|
}
|
|
}
|
|
for (j = i + 1; j < n; j++) {
|
|
factor = a[j][i] / a[i][i];
|
|
for(k = i; k < maug; k++) {
|
|
a[j][k] = a[j][k] - factor * a[i][k];
|
|
}
|
|
}
|
|
}
|
|
for (i = n - 1; i >= 0; i--) {
|
|
sum = 0;
|
|
for (j = i + 1; j<= n - 1; j++) {
|
|
sum = sum + x[j] * a[i][j];
|
|
}
|
|
x[i] =(a[i][maug - 1] - sum) / a[i][i];
|
|
}
|
|
return x;
|
|
},
|
|
|
|
gauss_jordan: function gauss_jordan(a, b) {
|
|
var m = jStat.aug(a, b);
|
|
var h = m.length;
|
|
var w = m[0].length;
|
|
var c = 0;
|
|
var x, y, y2;
|
|
// find max pivot
|
|
for (y = 0; y < h; y++) {
|
|
var maxrow = y;
|
|
for (y2 = y+1; y2 < h; y2++) {
|
|
if (Math.abs(m[y2][y]) > Math.abs(m[maxrow][y]))
|
|
maxrow = y2;
|
|
}
|
|
var tmp = m[y];
|
|
m[y] = m[maxrow];
|
|
m[maxrow] = tmp
|
|
for (y2 = y+1; y2 < h; y2++) {
|
|
c = m[y2][y] / m[y][y];
|
|
for (x = y; x < w; x++) {
|
|
m[y2][x] -= m[y][x] * c;
|
|
}
|
|
}
|
|
}
|
|
// backsubstitute
|
|
for (y = h-1; y >= 0; y--) {
|
|
c = m[y][y];
|
|
for (y2 = 0; y2 < y; y2++) {
|
|
for (x = w-1; x > y-1; x--) {
|
|
m[y2][x] -= m[y][x] * m[y2][y] / c;
|
|
}
|
|
}
|
|
m[y][y] /= c;
|
|
for (x = h; x < w; x++) {
|
|
m[y][x] /= c;
|
|
}
|
|
}
|
|
return m;
|
|
},
|
|
|
|
// solve equation
|
|
// Ax=b
|
|
// A is upper triangular matrix
|
|
// A=[[1,2,3],[0,4,5],[0,6,7]]
|
|
// b=[1,2,3]
|
|
// triaUpSolve(A,b) // -> [2.666,0.1666,1.666]
|
|
// if you use matrix style
|
|
// A=[[1,2,3],[0,4,5],[0,6,7]]
|
|
// b=[[1],[2],[3]]
|
|
// will return [[2.666],[0.1666],[1.666]]
|
|
triaUpSolve: function triaUpSolve(A, b) {
|
|
var size = A[0].length;
|
|
var x = jStat.zeros(1, size)[0];
|
|
var parts;
|
|
var matrix_mode = false;
|
|
|
|
if (b[0].length != undefined) {
|
|
b = b.map(function(i){ return i[0] });
|
|
matrix_mode = true;
|
|
}
|
|
|
|
jStat.arange(size - 1, -1, -1).forEach(function(i) {
|
|
parts = jStat.arange(i + 1, size).map(function(j) {
|
|
return x[j] * A[i][j];
|
|
});
|
|
x[i] = (b[i] - jStat.sum(parts)) / A[i][i];
|
|
});
|
|
|
|
if (matrix_mode)
|
|
return x.map(function(i){ return [i] });
|
|
return x;
|
|
},
|
|
|
|
triaLowSolve: function triaLowSolve(A, b) {
|
|
// like to triaUpSolve but A is lower triangular matrix
|
|
var size = A[0].length;
|
|
var x = jStat.zeros(1, size)[0];
|
|
var parts;
|
|
|
|
var matrix_mode=false;
|
|
if (b[0].length != undefined) {
|
|
b = b.map(function(i){ return i[0] });
|
|
matrix_mode = true;
|
|
}
|
|
|
|
jStat.arange(size).forEach(function(i) {
|
|
parts = jStat.arange(i).map(function(j) {
|
|
return A[i][j] * x[j];
|
|
});
|
|
x[i] = (b[i] - jStat.sum(parts)) / A[i][i];
|
|
})
|
|
|
|
if (matrix_mode)
|
|
return x.map(function(i){ return [i] });
|
|
return x;
|
|
},
|
|
|
|
|
|
// A -> [L,U]
|
|
// A=LU
|
|
// L is lower triangular matrix
|
|
// U is upper triangular matrix
|
|
lu: function lu(A) {
|
|
var size = A.length;
|
|
//var L=jStat.diagonal(jStat.ones(1,size)[0]);
|
|
var L = jStat.identity(size);
|
|
var R = jStat.zeros(A.length, A[0].length);
|
|
var parts;
|
|
jStat.arange(size).forEach(function(t) {
|
|
R[0][t] = A[0][t];
|
|
});
|
|
jStat.arange(1, size).forEach(function(l) {
|
|
jStat.arange(l).forEach(function(i) {
|
|
parts = jStat.arange(i).map(function(jj) {
|
|
return L[l][jj] * R[jj][i];
|
|
});
|
|
L[l][i] = (A[l][i] - jStat.sum(parts)) / R[i][i];
|
|
});
|
|
jStat.arange(l, size).forEach(function(j) {
|
|
parts = jStat.arange(l).map(function(jj) {
|
|
return L[l][jj] * R[jj][j];
|
|
});
|
|
R[l][j] = A[parts.length][j] - jStat.sum(parts);
|
|
});
|
|
});
|
|
return [L, R];
|
|
},
|
|
|
|
// A -> T
|
|
// A=TT'
|
|
// T is lower triangular matrix
|
|
cholesky: function cholesky(A) {
|
|
var size = A.length;
|
|
var T = jStat.zeros(A.length, A[0].length);
|
|
var parts;
|
|
jStat.arange(size).forEach(function(i) {
|
|
parts = jStat.arange(i).map(function(t) {
|
|
return Math.pow(T[i][t],2);
|
|
});
|
|
T[i][i] = Math.sqrt(A[i][i] - jStat.sum(parts));
|
|
jStat.arange(i + 1, size).forEach(function(j) {
|
|
parts = jStat.arange(i).map(function(t) {
|
|
return T[i][t] * T[j][t];
|
|
});
|
|
T[j][i] = (A[i][j] - jStat.sum(parts)) / T[i][i];
|
|
});
|
|
});
|
|
return T;
|
|
},
|
|
|
|
|
|
gauss_jacobi: function gauss_jacobi(a, b, x, r) {
|
|
var i = 0;
|
|
var j = 0;
|
|
var n = a.length;
|
|
var l = [];
|
|
var u = [];
|
|
var d = [];
|
|
var xv, c, h, xk;
|
|
for (; i < n; i++) {
|
|
l[i] = [];
|
|
u[i] = [];
|
|
d[i] = [];
|
|
for (j = 0; j < n; j++) {
|
|
if (i > j) {
|
|
l[i][j] = a[i][j];
|
|
u[i][j] = d[i][j] = 0;
|
|
} else if (i < j) {
|
|
u[i][j] = a[i][j];
|
|
l[i][j] = d[i][j] = 0;
|
|
} else {
|
|
d[i][j] = a[i][j];
|
|
l[i][j] = u[i][j] = 0;
|
|
}
|
|
}
|
|
}
|
|
h = jStat.multiply(jStat.multiply(jStat.inv(d), jStat.add(l, u)), -1);
|
|
c = jStat.multiply(jStat.inv(d), b);
|
|
xv = x;
|
|
xk = jStat.add(jStat.multiply(h, x), c);
|
|
i = 2;
|
|
while (Math.abs(jStat.norm(jStat.subtract(xk,xv))) > r) {
|
|
xv = xk;
|
|
xk = jStat.add(jStat.multiply(h, xv), c);
|
|
i++;
|
|
}
|
|
return xk;
|
|
},
|
|
|
|
gauss_seidel: function gauss_seidel(a, b, x, r) {
|
|
var i = 0;
|
|
var n = a.length;
|
|
var l = [];
|
|
var u = [];
|
|
var d = [];
|
|
var j, xv, c, h, xk;
|
|
for (; i < n; i++) {
|
|
l[i] = [];
|
|
u[i] = [];
|
|
d[i] = [];
|
|
for (j = 0; j < n; j++) {
|
|
if (i > j) {
|
|
l[i][j] = a[i][j];
|
|
u[i][j] = d[i][j] = 0;
|
|
} else if (i < j) {
|
|
u[i][j] = a[i][j];
|
|
l[i][j] = d[i][j] = 0;
|
|
} else {
|
|
d[i][j] = a[i][j];
|
|
l[i][j] = u[i][j] = 0;
|
|
}
|
|
}
|
|
}
|
|
h = jStat.multiply(jStat.multiply(jStat.inv(jStat.add(d, l)), u), -1);
|
|
c = jStat.multiply(jStat.inv(jStat.add(d, l)), b);
|
|
xv = x;
|
|
xk = jStat.add(jStat.multiply(h, x), c);
|
|
i = 2;
|
|
while (Math.abs(jStat.norm(jStat.subtract(xk, xv))) > r) {
|
|
xv = xk;
|
|
xk = jStat.add(jStat.multiply(h, xv), c);
|
|
i = i + 1;
|
|
}
|
|
return xk;
|
|
},
|
|
|
|
SOR: function SOR(a, b, x, r, w) {
|
|
var i = 0;
|
|
var n = a.length;
|
|
var l = [];
|
|
var u = [];
|
|
var d = [];
|
|
var j, xv, c, h, xk;
|
|
for (; i < n; i++) {
|
|
l[i] = [];
|
|
u[i] = [];
|
|
d[i] = [];
|
|
for (j = 0; j < n; j++) {
|
|
if (i > j) {
|
|
l[i][j] = a[i][j];
|
|
u[i][j] = d[i][j] = 0;
|
|
} else if (i < j) {
|
|
u[i][j] = a[i][j];
|
|
l[i][j] = d[i][j] = 0;
|
|
} else {
|
|
d[i][j] = a[i][j];
|
|
l[i][j] = u[i][j] = 0;
|
|
}
|
|
}
|
|
}
|
|
h = jStat.multiply(jStat.inv(jStat.add(d, jStat.multiply(l, w))),
|
|
jStat.subtract(jStat.multiply(d, 1 - w),
|
|
jStat.multiply(u, w)));
|
|
c = jStat.multiply(jStat.multiply(jStat.inv(jStat.add(d,
|
|
jStat.multiply(l, w))), b), w);
|
|
xv = x;
|
|
xk = jStat.add(jStat.multiply(h, x), c);
|
|
i = 2;
|
|
while (Math.abs(jStat.norm(jStat.subtract(xk, xv))) > r) {
|
|
xv = xk;
|
|
xk = jStat.add(jStat.multiply(h, xv), c);
|
|
i++;
|
|
}
|
|
return xk;
|
|
},
|
|
|
|
householder: function householder(a) {
|
|
var m = a.length;
|
|
var n = a[0].length;
|
|
var i = 0;
|
|
var w = [];
|
|
var p = [];
|
|
var alpha, r, k, j, factor;
|
|
for (; i < m - 1; i++) {
|
|
alpha = 0;
|
|
for (j = i + 1; j < n; j++)
|
|
alpha += (a[j][i] * a[j][i]);
|
|
factor = (a[i + 1][i] > 0) ? -1 : 1;
|
|
alpha = factor * Math.sqrt(alpha);
|
|
r = Math.sqrt((((alpha * alpha) - a[i + 1][i] * alpha) / 2));
|
|
w = jStat.zeros(m, 1);
|
|
w[i + 1][0] = (a[i + 1][i] - alpha) / (2 * r);
|
|
for (k = i + 2; k < m; k++) w[k][0] = a[k][i] / (2 * r);
|
|
p = jStat.subtract(jStat.identity(m, n),
|
|
jStat.multiply(jStat.multiply(w, jStat.transpose(w)), 2));
|
|
a = jStat.multiply(p, jStat.multiply(a, p));
|
|
}
|
|
return a;
|
|
},
|
|
|
|
// A -> [Q,R]
|
|
// Q is orthogonal matrix
|
|
// R is upper triangular
|
|
QR: (function() {
|
|
// x -> Q
|
|
// find a orthogonal matrix Q st.
|
|
// Qx=y
|
|
// y is [||x||,0,0,...]
|
|
|
|
// quick ref
|
|
var sum = jStat.sum;
|
|
var range = jStat.arange;
|
|
|
|
function qr2(x) {
|
|
// quick impletation
|
|
// https://www.stat.wisc.edu/~larget/math496/qr.html
|
|
|
|
var n = x.length;
|
|
var p = x[0].length;
|
|
|
|
var r = jStat.zeros(p, p);
|
|
x = jStat.copy(x);
|
|
|
|
var i,j,k;
|
|
for(j = 0; j < p; j++){
|
|
r[j][j] = Math.sqrt(sum(range(n).map(function(i){
|
|
return x[i][j] * x[i][j];
|
|
})));
|
|
for(i = 0; i < n; i++){
|
|
x[i][j] = x[i][j] / r[j][j];
|
|
}
|
|
for(k = j+1; k < p; k++){
|
|
r[j][k] = sum(range(n).map(function(i){
|
|
return x[i][j] * x[i][k];
|
|
}));
|
|
for(i = 0; i < n; i++){
|
|
x[i][k] = x[i][k] - x[i][j]*r[j][k];
|
|
}
|
|
}
|
|
}
|
|
return [x, r];
|
|
}
|
|
|
|
return qr2;
|
|
}()),
|
|
|
|
lstsq: (function() {
|
|
// solve least squard problem for Ax=b as QR decomposition way if b is
|
|
// [[b1],[b2],[b3]] form will return [[x1],[x2],[x3]] array form solution
|
|
// else b is [b1,b2,b3] form will return [x1,x2,x3] array form solution
|
|
function R_I(A) {
|
|
A = jStat.copy(A);
|
|
var size = A.length;
|
|
var I = jStat.identity(size);
|
|
jStat.arange(size - 1, -1, -1).forEach(function(i) {
|
|
jStat.sliceAssign(
|
|
I, { row: i }, jStat.divide(jStat.slice(I, { row: i }), A[i][i]));
|
|
jStat.sliceAssign(
|
|
A, { row: i }, jStat.divide(jStat.slice(A, { row: i }), A[i][i]));
|
|
jStat.arange(i).forEach(function(j) {
|
|
var c = jStat.multiply(A[j][i], -1);
|
|
var Aj = jStat.slice(A, { row: j });
|
|
var cAi = jStat.multiply(jStat.slice(A, { row: i }), c);
|
|
jStat.sliceAssign(A, { row: j }, jStat.add(Aj, cAi));
|
|
var Ij = jStat.slice(I, { row: j });
|
|
var cIi = jStat.multiply(jStat.slice(I, { row: i }), c);
|
|
jStat.sliceAssign(I, { row: j }, jStat.add(Ij, cIi));
|
|
})
|
|
});
|
|
return I;
|
|
}
|
|
|
|
function qr_solve(A, b){
|
|
var array_mode = false;
|
|
if (b[0].length === undefined) {
|
|
// [c1,c2,c3] mode
|
|
b = b.map(function(x){ return [x] });
|
|
array_mode = true;
|
|
}
|
|
var QR = jStat.QR(A);
|
|
var Q = QR[0];
|
|
var R = QR[1];
|
|
var attrs = A[0].length;
|
|
var Q1 = jStat.slice(Q,{col:{end:attrs}});
|
|
var R1 = jStat.slice(R,{row:{end:attrs}});
|
|
var RI = R_I(R1);
|
|
var Q2 = jStat.transpose(Q1);
|
|
|
|
if(Q2[0].length === undefined){
|
|
Q2 = [Q2]; // The confusing jStat.multifly implementation threat nature process again.
|
|
}
|
|
|
|
var x = jStat.multiply(jStat.multiply(RI, Q2), b);
|
|
|
|
if(x.length === undefined){
|
|
x = [[x]]; // The confusing jStat.multifly implementation threat nature process again.
|
|
}
|
|
|
|
|
|
if (array_mode)
|
|
return x.map(function(i){ return i[0] });
|
|
return x;
|
|
}
|
|
|
|
return qr_solve;
|
|
}()),
|
|
|
|
jacobi: function jacobi(a) {
|
|
var condition = 1;
|
|
var n = a.length;
|
|
var e = jStat.identity(n, n);
|
|
var ev = [];
|
|
var b, i, j, p, q, maxim, theta, s;
|
|
// condition === 1 only if tolerance is not reached
|
|
while (condition === 1) {
|
|
maxim = a[0][1];
|
|
p = 0;
|
|
q = 1;
|
|
for (i = 0; i < n; i++) {
|
|
for (j = 0; j < n; j++) {
|
|
if (i != j) {
|
|
if (maxim < Math.abs(a[i][j])) {
|
|
maxim = Math.abs(a[i][j]);
|
|
p = i;
|
|
q = j;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (a[p][p] === a[q][q])
|
|
theta = (a[p][q] > 0) ? Math.PI / 4 : -Math.PI / 4;
|
|
else
|
|
theta = Math.atan(2 * a[p][q] / (a[p][p] - a[q][q])) / 2;
|
|
s = jStat.identity(n, n);
|
|
s[p][p] = Math.cos(theta);
|
|
s[p][q] = -Math.sin(theta);
|
|
s[q][p] = Math.sin(theta);
|
|
s[q][q] = Math.cos(theta);
|
|
// eigen vector matrix
|
|
e = jStat.multiply(e, s);
|
|
b = jStat.multiply(jStat.multiply(jStat.inv(s), a), s);
|
|
a = b;
|
|
condition = 0;
|
|
for (i = 1; i < n; i++) {
|
|
for (j = 1; j < n; j++) {
|
|
if (i != j && Math.abs(a[i][j]) > 0.001) {
|
|
condition = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (i = 0; i < n; i++) ev.push(a[i][i]);
|
|
//returns both the eigenvalue and eigenmatrix
|
|
return [e, ev];
|
|
},
|
|
|
|
rungekutta: function rungekutta(f, h, p, t_j, u_j, order) {
|
|
var k1, k2, u_j1, k3, k4;
|
|
if (order === 2) {
|
|
while (t_j <= p) {
|
|
k1 = h * f(t_j, u_j);
|
|
k2 = h * f(t_j + h, u_j + k1);
|
|
u_j1 = u_j + (k1 + k2) / 2;
|
|
u_j = u_j1;
|
|
t_j = t_j + h;
|
|
}
|
|
}
|
|
if (order === 4) {
|
|
while (t_j <= p) {
|
|
k1 = h * f(t_j, u_j);
|
|
k2 = h * f(t_j + h / 2, u_j + k1 / 2);
|
|
k3 = h * f(t_j + h / 2, u_j + k2 / 2);
|
|
k4 = h * f(t_j +h, u_j + k3);
|
|
u_j1 = u_j + (k1 + 2 * k2 + 2 * k3 + k4) / 6;
|
|
u_j = u_j1;
|
|
t_j = t_j + h;
|
|
}
|
|
}
|
|
return u_j;
|
|
},
|
|
|
|
romberg: function romberg(f, a, b, order) {
|
|
var i = 0;
|
|
var h = (b - a) / 2;
|
|
var x = [];
|
|
var h1 = [];
|
|
var g = [];
|
|
var m, a1, j, k, I;
|
|
while (i < order / 2) {
|
|
I = f(a);
|
|
for (j = a, k = 0; j <= b; j = j + h, k++) x[k] = j;
|
|
m = x.length;
|
|
for (j = 1; j < m - 1; j++) {
|
|
I += (((j % 2) !== 0) ? 4 : 2) * f(x[j]);
|
|
}
|
|
I = (h / 3) * (I + f(b));
|
|
g[i] = I;
|
|
h /= 2;
|
|
i++;
|
|
}
|
|
a1 = g.length;
|
|
m = 1;
|
|
while (a1 !== 1) {
|
|
for (j = 0; j < a1 - 1; j++)
|
|
h1[j] = ((Math.pow(4, m)) * g[j + 1] - g[j]) / (Math.pow(4, m) - 1);
|
|
a1 = h1.length;
|
|
g = h1;
|
|
h1 = [];
|
|
m++;
|
|
}
|
|
return g;
|
|
},
|
|
|
|
richardson: function richardson(X, f, x, h) {
|
|
function pos(X, x) {
|
|
var i = 0;
|
|
var n = X.length;
|
|
var p;
|
|
for (; i < n; i++)
|
|
if (X[i] === x) p = i;
|
|
return p;
|
|
}
|
|
var h_min = Math.abs(x - X[pos(X, x) + 1]);
|
|
var i = 0;
|
|
var g = [];
|
|
var h1 = [];
|
|
var y1, y2, m, a, j;
|
|
while (h >= h_min) {
|
|
y1 = pos(X, x + h);
|
|
y2 = pos(X, x);
|
|
g[i] = (f[y1] - 2 * f[y2] + f[2 * y2 - y1]) / (h * h);
|
|
h /= 2;
|
|
i++;
|
|
}
|
|
a = g.length;
|
|
m = 1;
|
|
while (a != 1) {
|
|
for (j = 0; j < a - 1; j++)
|
|
h1[j] = ((Math.pow(4, m)) * g[j + 1] - g[j]) / (Math.pow(4, m) - 1);
|
|
a = h1.length;
|
|
g = h1;
|
|
h1 = [];
|
|
m++;
|
|
}
|
|
return g;
|
|
},
|
|
|
|
simpson: function simpson(f, a, b, n) {
|
|
var h = (b - a) / n;
|
|
var I = f(a);
|
|
var x = [];
|
|
var j = a;
|
|
var k = 0;
|
|
var i = 1;
|
|
var m;
|
|
for (; j <= b; j = j + h, k++)
|
|
x[k] = j;
|
|
m = x.length;
|
|
for (; i < m - 1; i++) {
|
|
I += ((i % 2 !== 0) ? 4 : 2) * f(x[i]);
|
|
}
|
|
return (h / 3) * (I + f(b));
|
|
},
|
|
|
|
hermite: function hermite(X, F, dF, value) {
|
|
var n = X.length;
|
|
var p = 0;
|
|
var i = 0;
|
|
var l = [];
|
|
var dl = [];
|
|
var A = [];
|
|
var B = [];
|
|
var j;
|
|
for (; i < n; i++) {
|
|
l[i] = 1;
|
|
for (j = 0; j < n; j++) {
|
|
if (i != j) l[i] *= (value - X[j]) / (X[i] - X[j]);
|
|
}
|
|
dl[i] = 0;
|
|
for (j = 0; j < n; j++) {
|
|
if (i != j) dl[i] += 1 / (X [i] - X[j]);
|
|
}
|
|
A[i] = (1 - 2 * (value - X[i]) * dl[i]) * (l[i] * l[i]);
|
|
B[i] = (value - X[i]) * (l[i] * l[i]);
|
|
p += (A[i] * F[i] + B[i] * dF[i]);
|
|
}
|
|
return p;
|
|
},
|
|
|
|
lagrange: function lagrange(X, F, value) {
|
|
var p = 0;
|
|
var i = 0;
|
|
var j, l;
|
|
var n = X.length;
|
|
for (; i < n; i++) {
|
|
l = F[i];
|
|
for (j = 0; j < n; j++) {
|
|
// calculating the lagrange polynomial L_i
|
|
if (i != j) l *= (value - X[j]) / (X[i] - X[j]);
|
|
}
|
|
// adding the lagrange polynomials found above
|
|
p += l;
|
|
}
|
|
return p;
|
|
},
|
|
|
|
cubic_spline: function cubic_spline(X, F, value) {
|
|
var n = X.length;
|
|
var i = 0, j;
|
|
var A = [];
|
|
var B = [];
|
|
var alpha = [];
|
|
var c = [];
|
|
var h = [];
|
|
var b = [];
|
|
var d = [];
|
|
for (; i < n - 1; i++)
|
|
h[i] = X[i + 1] - X[i];
|
|
alpha[0] = 0;
|
|
for (i = 1; i < n - 1; i++) {
|
|
alpha[i] = (3 / h[i]) * (F[i + 1] - F[i]) -
|
|
(3 / h[i-1]) * (F[i] - F[i-1]);
|
|
}
|
|
for (i = 1; i < n - 1; i++) {
|
|
A[i] = [];
|
|
B[i] = [];
|
|
A[i][i-1] = h[i-1];
|
|
A[i][i] = 2 * (h[i - 1] + h[i]);
|
|
A[i][i+1] = h[i];
|
|
B[i][0] = alpha[i];
|
|
}
|
|
c = jStat.multiply(jStat.inv(A), B);
|
|
for (j = 0; j < n - 1; j++) {
|
|
b[j] = (F[j + 1] - F[j]) / h[j] - h[j] * (c[j + 1][0] + 2 * c[j][0]) / 3;
|
|
d[j] = (c[j + 1][0] - c[j][0]) / (3 * h[j]);
|
|
}
|
|
for (j = 0; j < n; j++) {
|
|
if (X[j] > value) break;
|
|
}
|
|
j -= 1;
|
|
return F[j] + (value - X[j]) * b[j] + jStat.sq(value-X[j]) *
|
|
c[j] + (value - X[j]) * jStat.sq(value - X[j]) * d[j];
|
|
},
|
|
|
|
gauss_quadrature: function gauss_quadrature() {
|
|
throw new Error('gauss_quadrature not yet implemented');
|
|
},
|
|
|
|
PCA: function PCA(X) {
|
|
var m = X.length;
|
|
var n = X[0].length;
|
|
var i = 0;
|
|
var j, temp1;
|
|
var u = [];
|
|
var D = [];
|
|
var result = [];
|
|
var temp2 = [];
|
|
var Y = [];
|
|
var Bt = [];
|
|
var B = [];
|
|
var C = [];
|
|
var V = [];
|
|
var Vt = [];
|
|
for (i = 0; i < m; i++) {
|
|
u[i] = jStat.sum(X[i]) / n;
|
|
}
|
|
for (i = 0; i < n; i++) {
|
|
B[i] = [];
|
|
for(j = 0; j < m; j++) {
|
|
B[i][j] = X[j][i] - u[j];
|
|
}
|
|
}
|
|
B = jStat.transpose(B);
|
|
for (i = 0; i < m; i++) {
|
|
C[i] = [];
|
|
for (j = 0; j < m; j++) {
|
|
C[i][j] = (jStat.dot([B[i]], [B[j]])) / (n - 1);
|
|
}
|
|
}
|
|
result = jStat.jacobi(C);
|
|
V = result[0];
|
|
D = result[1];
|
|
Vt = jStat.transpose(V);
|
|
for (i = 0; i < D.length; i++) {
|
|
for (j = i; j < D.length; j++) {
|
|
if(D[i] < D[j]) {
|
|
temp1 = D[i];
|
|
D[i] = D[j];
|
|
D[j] = temp1;
|
|
temp2 = Vt[i];
|
|
Vt[i] = Vt[j];
|
|
Vt[j] = temp2;
|
|
}
|
|
}
|
|
}
|
|
Bt = jStat.transpose(B);
|
|
for (i = 0; i < m; i++) {
|
|
Y[i] = [];
|
|
for (j = 0; j < Bt.length; j++) {
|
|
Y[i][j] = jStat.dot([Vt[i]], [Bt[j]]);
|
|
}
|
|
}
|
|
return [X, D, Vt, Y];
|
|
}
|
|
});
|
|
|
|
// extend jStat.fn with methods that require one argument
|
|
(function(funcs) {
|
|
for (var i = 0; i < funcs.length; i++) (function(passfunc) {
|
|
jStat.fn[passfunc] = function(arg, func) {
|
|
var tmpthis = this;
|
|
// check for callback
|
|
if (func) {
|
|
setTimeout(function() {
|
|
func.call(tmpthis, jStat.fn[passfunc].call(tmpthis, arg));
|
|
}, 15);
|
|
return this;
|
|
}
|
|
if (typeof jStat[passfunc](this, arg) === 'number')
|
|
return jStat[passfunc](this, arg);
|
|
else
|
|
return jStat(jStat[passfunc](this, arg));
|
|
};
|
|
}(funcs[i]));
|
|
}('add divide multiply subtract dot pow exp log abs norm angle'.split(' ')));
|
|
|
|
}(jStat, Math));
|