This repository has been archived on 2023-03-25. You can view files and clone it, but cannot push or open issues or pull requests.
mightyscape-1.1-deprecated/extensions/fablabchemnitz/papercraft/openjscad/node_modules/sylvester/lib/matrix.js

1388 lines
33 KiB
JavaScript

'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.Matrix = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _fs = require('fs');
var fs = _interopRequireWildcard(_fs);
var _sylvester = require('./sylvester');
var _vector = require('./vector');
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function sign(x) {
return x < 0 ? -1 : 1;
}
// augment a matrix M with identity rows/cols
function identSize(M, m, n, k) {
var e = M.elements;
var i = k - 1;
while (i--) {
var row = [];
for (var j = 0; j < n; j++) {
row.push(j === i ? 1 : 0);
}
e.unshift(row);
}
for (var _i = k - 1; _i < m; _i++) {
while (e[_i].length < n) {
e[_i].unshift(0);
}
}
return Matrix.create(e); // eslint-disable-line no-use-before-define
}
function pca(X) {
var Sigma = X.transpose().x(X).x(1 / X.rows());
var svd = Sigma.svd();
return {
U: svd.U,
S: svd.S
};
}
var Matrix = exports.Matrix = function () {
function Matrix() {
_classCallCheck(this, Matrix);
}
_createClass(Matrix, [{
key: 'solve',
// solve a system of linear equations (work in progress)
value: function solve(b) {
var lu = this.lu();
b = lu.P.x(b);
var y = lu.L.forwardSubstitute(b);
var x = lu.U.backSubstitute(y);
return lu.P.x(x);
// return this.inv().x(b);
}
// project a matrix onto a lower dim
}, {
key: 'pcaProject',
value: function pcaProject(k) {
var U = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : pca(this).U;
var Ureduce = U.slice(1, U.rows(), 1, k);
return {
Z: this.x(Ureduce),
U: U
};
}
// recover a matrix to a higher dimension
}, {
key: 'pcaRecover',
value: function pcaRecover(U) {
var k = this.cols();
var Ureduce = U.slice(1, U.rows(), 1, k);
return this.x(Ureduce.transpose());
}
// grab the upper triangular part of the matrix
}, {
key: 'triu',
value: function triu(k) {
if (!k) {
k = 0;
}
return this.map(function (x, i, j) {
return j - i >= k ? x : 0;
});
}
// unroll a matrix into a vector
}, {
key: 'unroll',
value: function unroll() {
var v = [];
for (var i = 1; i <= this.cols(); i++) {
for (var j = 1; j <= this.rows(); j++) {
v.push(this.e(j, i));
}
}
return _vector.Vector.create(v);
}
// return a sub-block of the matrix
}, {
key: 'slice',
value: function slice(startRow, endRow, startCol, endCol) {
var x = [];
if (endRow === 0) {
endRow = this.rows();
}
if (endCol === 0) {
endCol = this.cols();
}
for (var i = startRow; i <= endRow; i++) {
var row = [];
for (var j = startCol; j <= endCol; j++) {
row.push(this.e(i, j));
}
x.push(row);
}
return Matrix.create(x);
}
// Returns element (i,j) of the matrix
}, {
key: 'e',
value: function e(i, j) {
if (i < 1 || i > this.elements.length || j < 1 || j > this.elements[0].length) {
return null;
}
return this.elements[i - 1][j - 1];
}
// Returns row k of the matrix as a vector
}, {
key: 'row',
value: function row(i) {
if (i > this.elements.length) {
return null;
}
return _vector.Vector.create(this.elements[i - 1]);
}
// Returns column k of the matrix as a vector
}, {
key: 'col',
value: function col(j) {
if (j > this.elements[0].length) {
return null;
}
var col = [];
var n = this.elements.length;
for (var i = 0; i < n; i++) {
col.push(this.elements[i][j - 1]);
}
return _vector.Vector.create(col);
}
// Returns the number of rows/columns the matrix has
}, {
key: 'dimensions',
value: function dimensions() {
return {
rows: this.elements.length,
cols: this.elements[0].length
};
}
// Returns the number of rows in the matrix
}, {
key: 'rows',
value: function rows() {
return this.elements.length;
}
// Returns the number of columns in the matrix
}, {
key: 'cols',
value: function cols() {
return this.elements[0].length;
}
}, {
key: 'approxEql',
value: function approxEql(matrix) {
return this.eql(matrix, _sylvester.Sylvester.approxPrecision);
}
// Returns true iff the matrix is equal to the argument. You can supply
// a vector as the argument, in which case the receiver must be a
// one-column matrix equal to the vector.
}, {
key: 'eql',
value: function eql(matrix, precision) {
var M = matrix.elements || matrix;
if (typeof M[0][0] === 'undefined') {
M = Matrix.create(M).elements;
}
if (this.elements.length !== M.length || this.elements[0].length !== M[0].length) {
return false;
}
var i = this.elements.length;
var nj = this.elements[0].length;
var j = void 0;
while (i--) {
j = nj;
while (j--) {
if (Math.abs(this.elements[i][j] - M[i][j]) > (precision || _sylvester.Sylvester.precision)) {
return false;
}
}
}
return true;
}
// Returns a copy of the matrix
}, {
key: 'dup',
value: function dup() {
return Matrix.create(this.elements);
}
// Maps the matrix to another matrix (of the same dimensions) according to the given function
}, {
key: 'map',
value: function map(fn) {
var els = [];
var i = this.elements.length;
var nj = this.elements[0].length;
var j = void 0;
while (i--) {
j = nj;
els[i] = [];
while (j--) {
els[i][j] = fn(this.elements[i][j], i + 1, j + 1);
}
}
return Matrix.create(els);
}
// Returns true iff the argument has the same dimensions as the matrix
}, {
key: 'isSameSizeAs',
value: function isSameSizeAs(matrix) {
var M = matrix.elements || matrix;
if (typeof M[0][0] === 'undefined') {
M = Matrix.create(M).elements;
}
return this.elements.length === M.length && this.elements[0].length === M[0].length;
}
// Returns the result of adding the argument to the matrix
}, {
key: 'add',
value: function add(matrix) {
if (typeof matrix === 'number') {
return this.map(function (x) {
return x + matrix;
});
}
var M = matrix.elements || matrix;
if (typeof M[0][0] === 'undefined') {
M = Matrix.create(M).elements;
}
if (!this.isSameSizeAs(M)) {
return null;
}
return this.map(function (x, i, j) {
return x + M[i - 1][j - 1];
});
}
// Returns the result of subtracting the argument from the matrix
}, {
key: 'subtract',
value: function subtract(matrix) {
if (typeof matrix === 'number') {
return this.map(function (x) {
return x - matrix;
});
}
var M = matrix.elements || matrix;
if (typeof M[0][0] === 'undefined') {
M = Matrix.create(M).elements;
}
if (!this.isSameSizeAs(M)) {
return null;
}
return this.map(function (x, i, j) {
return x - M[i - 1][j - 1];
});
}
// Returns true iff the matrix can multiply the argument from the left
}, {
key: 'canMultiplyFromLeft',
value: function canMultiplyFromLeft(matrix) {
var M = matrix.elements || matrix;
if (typeof M[0][0] === 'undefined') {
M = Matrix.create(M).elements;
}
// this.columns should equal matrix.rows
return this.elements[0].length === M.length;
}
// Returns the result of a multiplication-style operation the matrix from the right by the argument.
// If the argument is a scalar then just operate on all the elements. If the argument is
// a vector, a vector is returned, which saves you having to remember calling
// col(1) on the result.
}, {
key: 'mulOp',
value: function mulOp(matrix, op) {
if (!matrix.elements) {
return this.map(function (x) {
return op(x, matrix);
});
}
var returnVector = Boolean(matrix.modulus);
var M = matrix.elements || matrix;
if (typeof M[0][0] === 'undefined') {
M = Matrix.create(M).elements;
}
if (!this.canMultiplyFromLeft(M)) {
return null;
}
var e = this.elements;
var rowThis = void 0;
var rowElem = void 0;
var elements = [];
var sum = void 0;
var m = e.length;
var n = M[0].length;
var o = e[0].length;
var i = m;
var j = void 0;
var k = void 0;
while (i--) {
rowElem = [];
rowThis = e[i];
j = n;
while (j--) {
sum = 0;
k = o;
while (k--) {
sum += op(rowThis[k], M[k][j]);
}
rowElem[j] = sum;
}
elements[i] = rowElem;
}
var output = Matrix.create(elements);
return returnVector ? output.col(1) : output;
}
// Returns the result of dividing the matrix from the right by the argument.
// If the argument is a scalar then just divide all the elements. If the argument is
// a vector, a vector is returned, which saves you having to remember calling
// col(1) on the result.
}, {
key: 'div',
value: function div(matrix) {
return this.mulOp(matrix, function (x, y) {
return x / y;
});
}
// Returns the result of multiplying the matrix from the right by the argument.
// If the argument is a scalar then just multiply all the elements. If the argument is
// a vector, a vector is returned, which saves you having to remember calling
// col(1) on the result.
}, {
key: 'multiply',
value: function multiply(matrix) {
return this.mulOp(matrix, function (x, y) {
return x * y;
});
}
}, {
key: 'x',
value: function x(matrix) {
return this.multiply(matrix);
}
}, {
key: 'elementMultiply',
value: function elementMultiply(v) {
return this.map(function (k, i, j) {
return v.e(i, j) * k;
});
}
// sum all elements in the matrix
}, {
key: 'sum',
value: function sum() {
var sum = 0;
this.map(function (x) {
// eslint-disable-line array-callback-return
sum += x;
});
return sum;
}
// Returns a Vector of each colum averaged.
}, {
key: 'mean',
value: function mean() {
var dim = this.dimensions();
var r = [];
for (var i = 1; i <= dim.cols; i++) {
r.push(this.col(i).sum() / dim.rows);
}
return _vector.Vector.create(r);
}
// Returns a Vector of each column's standard deviation
}, {
key: 'std',
value: function std() {
var dim = this.dimensions();
var mMean = this.mean();
var r = [];
for (var i = 1; i <= dim.cols; i++) {
var meanDiff = this.col(i).subtract(mMean.e(i));
meanDiff = meanDiff.multiply(meanDiff);
r.push(Math.sqrt(meanDiff.sum() / dim.rows));
}
return _vector.Vector.create(r);
}
}, {
key: 'column',
value: function column(n) {
return this.col(n);
}
// element-wise log
}, {
key: 'log',
value: function log() {
return this.map(function (x) {
return Math.log(x);
});
}
// Returns a submatrix taken from the matrix
// Argument order is: start row, start col, nrows, ncols
// Element selection wraps if the required index is outside the matrix's bounds, so you could
// use this to perform row/column cycling or copy-augmenting.
}, {
key: 'minor',
value: function minor(a, b, c, d) {
var elements = [];
var ni = c;
var i = void 0;
var nj = void 0;
var j = void 0;
var rows = this.elements.length;
var cols = this.elements[0].length;
while (ni--) {
i = c - ni - 1;
elements[i] = [];
nj = d;
while (nj--) {
j = d - nj - 1;
elements[i][j] = this.elements[(a + i - 1) % rows][(b + j - 1) % cols];
}
}
return Matrix.create(elements);
}
// Returns the transpose of the matrix
}, {
key: 'transpose',
value: function transpose() {
var rows = this.elements.length;
var cols = this.elements[0].length;
var elements = [];
var i = cols;
var j = void 0;
while (i--) {
j = rows;
elements[i] = [];
while (j--) {
elements[i][j] = this.elements[j][i];
}
}
return Matrix.create(elements);
}
// Returns true iff the matrix is square
}, {
key: 'isSquare',
value: function isSquare() {
return this.elements.length === this.elements[0].length;
}
// Returns the (absolute) largest element of the matrix
}, {
key: 'max',
value: function max() {
var m = 0;
var i = this.elements.length;
var nj = this.elements[0].length;
var j = void 0;
while (i--) {
j = nj;
while (j--) {
if (Math.abs(this.elements[i][j]) > Math.abs(m)) {
m = this.elements[i][j];
}
}
}
return m;
}
// Returns the indeces of the first match found by reading row-by-row from left to right
}, {
key: 'indexOf',
value: function indexOf(x) {
var ni = this.elements.length;
var i = void 0;
var nj = this.elements[0].length;
var j = void 0;
for (i = 0; i < ni; i++) {
for (j = 0; j < nj; j++) {
if (this.elements[i][j] === x) {
return {
i: i + 1,
j: j + 1
};
}
}
}
return null;
}
// If the matrix is square, returns the diagonal elements as a vector.
// Otherwise, returns null.
}, {
key: 'diagonal',
value: function diagonal() {
if (!this.isSquare) {
return null;
}
var els = [];
var n = this.elements.length;
for (var i = 0; i < n; i++) {
els.push(this.elements[i][i]);
}
return _vector.Vector.create(els);
}
// Make the matrix upper (right) triangular by Gaussian elimination.
// This method only adds multiples of rows to other rows. No rows are
// scaled up or switched, and the determinant is preserved.
}, {
key: 'toRightTriangular',
value: function toRightTriangular() {
var M = this.dup();
var els = void 0;
var n = this.elements.length;
var i = void 0;
var j = void 0;
var np = this.elements[0].length;
var p = void 0;
for (i = 0; i < n; i++) {
if (M.elements[i][i] === 0) {
for (j = i + 1; j < n; j++) {
if (M.elements[j][i] !== 0) {
els = [];
for (p = 0; p < np; p++) {
els.push(M.elements[i][p] + M.elements[j][p]);
}
M.elements[i] = els;
break;
}
}
}
if (M.elements[i][i] !== 0) {
for (j = i + 1; j < n; j++) {
var multiplier = M.elements[j][i] / M.elements[i][i];
els = [];
for (p = 0; p < np; p++) {
// Elements with column numbers up to an including the number
// of the row that we're subtracting can safely be set straight to
// zero, since that's the point of this routine and it avoids having
// to loop over and correct rounding errors later
els.push(p <= i ? 0 : M.elements[j][p] - M.elements[i][p] * multiplier);
}
M.elements[j] = els;
}
}
}
return M;
}
}, {
key: 'toUpperTriangular',
value: function toUpperTriangular() {
return this.toRightTriangular();
}
// Returns the determinant for square matrices
}, {
key: 'determinant',
value: function determinant() {
if (!this.isSquare()) {
return null;
}
if (this.cols === 1 && this.rows === 1) {
return this.row(1);
}
if (this.cols === 0 && this.rows === 0) {
return 1;
}
var M = this.toRightTriangular();
var det = M.elements[0][0];
var n = M.elements.length;
for (var i = 1; i < n; i++) {
det *= M.elements[i][i];
}
return det;
}
}, {
key: 'det',
value: function det() {
return this.determinant();
}
// Returns true iff the matrix is singular
}, {
key: 'isSingular',
value: function isSingular() {
return this.isSquare() && this.determinant() === 0;
}
// Returns the trace for square matrices
}, {
key: 'trace',
value: function trace() {
if (!this.isSquare()) {
return null;
}
var tr = this.elements[0][0];
var n = this.elements.length;
for (var i = 1; i < n; i++) {
tr += this.elements[i][i];
}
return tr;
}
}, {
key: 'tr',
value: function tr() {
return this.trace();
}
// Returns the rank of the matrix
}, {
key: 'rank',
value: function rank() {
var M = this.toRightTriangular();
var rank = 0;
var i = this.elements.length;
var nj = this.elements[0].length;
var j = void 0;
while (i--) {
j = nj;
while (j--) {
if (Math.abs(M.elements[i][j]) > _sylvester.Sylvester.precision) {
rank++;
break;
}
}
}
return rank;
}
}, {
key: 'rk',
value: function rk() {
return this.rank();
}
// Returns the result of attaching the given argument to the right-hand side of the matrix
}, {
key: 'augment',
value: function augment(matrix) {
var M = matrix.elements || matrix;
if (typeof M[0][0] === 'undefined') {
M = Matrix.create(M).elements;
}
var T = this.dup();
var cols = T.elements[0].length;
var i = T.elements.length;
var nj = M[0].length;
var j = void 0;
if (i !== M.length) {
return null;
}
while (i--) {
j = nj;
while (j--) {
T.elements[i][cols + j] = M[i][j];
}
}
return T;
}
// Returns the inverse (if one exists) using Gauss-Jordan
}, {
key: 'inverse',
value: function inverse() {
if (!this.isSquare() || this.isSingular()) {
return null;
}
var n = this.elements.length;
var i = n;
var j = void 0;
var M = this.augment(Matrix.I(n)).toRightTriangular();
var np = M.elements[0].length;
var p = void 0;
var els = void 0;
var divisor = void 0;
var inverseElements = [];
// Matrix is non-singular so there will be no zeros on the diagonal
// Cycle through rows from last to first
var newElement = void 0;
while (i--) {
// First, normalise diagonal elements to 1
els = [];
inverseElements[i] = [];
divisor = M.elements[i][i];
for (p = 0; p < np; p++) {
newElement = M.elements[i][p] / divisor;
els.push(newElement);
// Shuffle off the current row of the right hand side into the results
// array as it will not be modified by later runs through this loop
if (p >= n) {
inverseElements[i].push(newElement);
}
}
M.elements[i] = els;
// Then, subtract this row from those above it to
// give the identity matrix on the left hand side
j = i;
while (j--) {
els = [];
for (p = 0; p < np; p++) {
els.push(M.elements[j][p] - M.elements[i][p] * M.elements[j][i]);
}
M.elements[j] = els;
}
}
return Matrix.create(inverseElements);
}
}, {
key: 'inv',
value: function inv() {
return this.inverse();
}
// Returns the result of rounding all the elements
}, {
key: 'round',
value: function round() {
return this.map(function (x) {
return Math.round(x);
});
}
// Returns a copy of the matrix with elements set to the given value if they
// differ from it by less than Sylvester.precision
}, {
key: 'snapTo',
value: function snapTo(x) {
return this.map(function (p) {
return Math.abs(p - x) <= _sylvester.Sylvester.precision ? x : p;
});
}
// Returns a string representation of the matrix
}, {
key: 'inspect',
value: function inspect() {
var matrixRows = [];
var n = this.elements.length;
for (var i = 0; i < n; i++) {
matrixRows.push(_vector.Vector.create(this.elements[i]).inspect());
}
return matrixRows.join('\n');
}
// Returns a array representation of the matrix
}, {
key: 'toArray',
value: function toArray() {
var matrixRows = [];
var n = this.elements.length;
for (var i = 0; i < n; i++) {
matrixRows.push(this.elements[i]);
}
return matrixRows;
}
// Set the matrix's elements from an array. If the argument passed
// is a vector, the resulting matrix will be a single column.
}, {
key: 'setElements',
value: function setElements(els) {
var i = void 0;
var j = void 0;
var elements = els.elements || els;
if (typeof elements[0][0] !== 'undefined') {
i = elements.length;
this.elements = [];
while (i--) {
j = elements[i].length;
this.elements[i] = [];
while (j--) {
this.elements[i][j] = elements[i][j];
}
}
return this;
}
var n = elements.length;
this.elements = [];
for (i = 0; i < n; i++) {
this.elements.push([elements[i]]);
}
return this;
}
// return the indexes of the columns with the largest value
// for each row
}, {
key: 'maxColumnIndexes',
value: function maxColumnIndexes() {
var maxes = [];
for (var i = 1; i <= this.rows(); i++) {
var max = null;
var maxIndex = -1;
for (var j = 1; j <= this.cols(); j++) {
if (max === null || this.e(i, j) > max) {
max = this.e(i, j);
maxIndex = j;
}
}
maxes.push(maxIndex);
}
return _vector.Vector.create(maxes);
}
// return the largest values in each row
}, {
key: 'maxColumns',
value: function maxColumns() {
var maxes = [];
for (var i = 1; i <= this.rows(); i++) {
var max = null;
for (var j = 1; j <= this.cols(); j++) {
if (max === null || this.e(i, j) > max) {
max = this.e(i, j);
}
}
maxes.push(max);
}
return _vector.Vector.create(maxes);
}
// return the indexes of the columns with the smallest values
// for each row
}, {
key: 'minColumnIndexes',
value: function minColumnIndexes() {
var mins = [];
for (var i = 1; i <= this.rows(); i++) {
var min = null;
var minIndex = -1;
for (var j = 1; j <= this.cols(); j++) {
if (min === null || this.e(i, j) < min) {
min = this.e(i, j);
minIndex = j;
}
}
mins.push(minIndex);
}
return _vector.Vector.create(mins);
}
// return the smallest values in each row
}, {
key: 'minColumns',
value: function minColumns() {
var mins = [];
for (var i = 1; i <= this.rows(); i++) {
var min = null;
for (var j = 1; j <= this.cols(); j++) {
if (min === null || this.e(i, j) < min) {
min = this.e(i, j);
}
}
mins.push(min);
}
return _vector.Vector.create(mins);
}
// perorm a partial pivot on the matrix. essentially move the largest
// row below-or-including the pivot and replace the pivot's row with it.
// a pivot matrix is returned so multiplication can perform the transform.
}, {
key: 'partialPivot',
value: function partialPivot(k, j, P, A) {
var maxIndex = 0;
var maxValue = 0;
for (var i = k; i <= A.rows(); i++) {
if (Math.abs(A.e(i, j)) > maxValue) {
maxValue = Math.abs(A.e(k, j));
maxIndex = i;
}
}
if (maxIndex !== k) {
var tmp = A.elements[k - 1];
A.elements[k - 1] = A.elements[maxIndex - 1];
A.elements[maxIndex - 1] = tmp;
P.elements[k - 1][k - 1] = 0;
P.elements[k - 1][maxIndex - 1] = 1;
P.elements[maxIndex - 1][maxIndex - 1] = 0;
P.elements[maxIndex - 1][k - 1] = 1;
}
return P;
}
// solve lower-triangular matrix * x = b via forward substitution
}, {
key: 'forwardSubstitute',
value: function forwardSubstitute(b) {
var xa = [];
for (var i = 1; i <= this.rows(); i++) {
var w = 0;
for (var j = 1; j < i; j++) {
w += this.e(i, j) * xa[j - 1];
}
xa.push((b.e(i) - w) / this.e(i, i));
}
return _vector.Vector.create(xa);
}
// solve an upper-triangular matrix * x = b via back substitution
}, {
key: 'backSubstitute',
value: function backSubstitute(b) {
var xa = [];
for (var i = this.rows(); i > 0; i--) {
var w = 0;
for (var j = this.cols(); j > i; j--) {
w += this.e(i, j) * xa[this.rows() - j];
}
xa.push((b.e(i) - w) / this.e(i, i));
}
return _vector.Vector.create(xa.reverse());
}
}, {
key: 'svdJs',
value: function svdJs() {
var A = this;
var V = Matrix.I(A.rows());
var S = A.transpose();
var U = Matrix.I(A.cols());
var err = Number.MAX_VALUE;
var i = 0;
var maxLoop = 100;
while (err > 2.2737e-13 && i < maxLoop) {
var qr = S.transpose().qrJs();
S = qr.R;
V = V.x(qr.Q);
qr = S.transpose().qrJs();
U = U.x(qr.Q);
S = qr.R;
var e = S.triu(1).unroll().norm();
var f = S.diagonal().norm();
if (f === 0) {
f = 1;
}
err = e / f;
i++;
}
var ss = S.diagonal();
var s = [];
for (var _i2 = 1; _i2 <= ss.cols(); _i2++) {
var ssn = ss.e(_i2);
s.push(Math.abs(ssn));
if (ssn < 0) {
for (var j = 0; j < U.rows(); j++) {
V.elements[j][_i2 - 1] = -V.elements[j][_i2 - 1];
}
}
}
return {
U: U,
S: _vector.Vector.create(s).toDiagonalMatrix(),
V: V
};
}
// QR decomposition in pure javascript
}, {
key: 'qrJs',
value: function qrJs() {
var m = this.rows();
var n = this.cols();
var Q = Matrix.I(m);
var A = this;
for (var k = 1; k < Math.min(m, n); k++) {
var ak = A.slice(k, 0, k, k).col(1);
var oneZero = [1];
while (oneZero.length <= m - k) {
oneZero.push(0);
}
oneZero = _vector.Vector.create(oneZero);
var vk = ak.add(oneZero.x(ak.norm() * sign(ak.e(1))));
var Vk = Matrix.create(vk);
var Hk = Matrix.I(m - k + 1).subtract(Vk.x(2).x(Vk.transpose()).div(Vk.transpose().x(Vk).e(1, 1)));
var Qk = identSize(Hk, m, n, k);
A = Qk.x(A);
// slow way to compute Q
Q = Q.x(Qk);
}
return {
Q: Q,
R: A
};
}
// pure Javascript LU factorization
}, {
key: 'luJs',
value: function luJs() {
var A = this.dup();
var L = Matrix.I(A.rows());
var P = Matrix.I(A.rows());
var U = Matrix.Zeros(A.rows(), A.cols());
var p = 1;
for (var k = 1; k <= Math.min(A.cols(), A.rows()); k++) {
P = A.partialPivot(k, p, P, A, L);
for (var i = k + 1; i <= A.rows(); i++) {
var l = A.e(i, p) / A.e(k, p);
L.elements[i - 1][k - 1] = l;
for (var j = k + 1; j <= A.cols(); j++) {
A.elements[i - 1][j - 1] -= A.e(k, j) * l;
}
}
for (var _j = k; _j <= A.cols(); _j++) {
U.elements[k - 1][_j - 1] = A.e(k, _j);
}
if (p < A.cols()) {
p++;
}
}
return {
L: L,
U: U,
P: P
};
}
// Constructor function
}], [{
key: 'create',
value: function create(aElements) {
var M = new Matrix().setElements(aElements);
return M;
}
// Identity matrix of size n
}, {
key: 'I',
value: function I(n) {
var els = [];
var i = n;
var j = void 0;
while (i--) {
j = n;
els[i] = [];
while (j--) {
els[i][j] = i === j ? 1 : 0;
}
}
return Matrix.create(els);
}
}, {
key: 'loadFile',
value: function loadFile(file) {
var contents = fs.readFileSync(file, 'utf-8');
var matrix = [];
var rowArray = contents.split('\n');
for (var i = 0; i < rowArray.length; i++) {
var d = rowArray[i].split(',');
if (d.length > 1) {
matrix.push(d);
}
}
var M = new Matrix();
return M.setElements(matrix);
}
// Diagonal matrix - all off-diagonal elements are zero
}, {
key: 'Diagonal',
value: function Diagonal(elements) {
var i = elements.length;
var M = Matrix.I(i);
while (i--) {
M.elements[i][i] = elements[i];
}
return M;
}
// Rotation matrix about some axis. If no axis is
// supplied, assume we're after a 2D transform
}, {
key: 'Rotation',
value: function Rotation(theta, a) {
if (!a) {
return Matrix.create([[Math.cos(theta), -Math.sin(theta)], [Math.sin(theta), Math.cos(theta)]]);
}
var axis = a.dup();
if (axis.elements.length !== 3) {
return null;
}
var mod = axis.modulus();
var x = axis.elements[0] / mod;
var y = axis.elements[1] / mod;
var z = axis.elements[2] / mod;
var s = Math.sin(theta);
// Formula derived here: http://www.gamedev.net/reference/articles/article1199.asp
// That proof rotates the co-ordinate system so theta
// becomes -theta and sin becomes -sin here.
var c = Math.cos(theta);
var t = 1 - c;
return Matrix.create([[t * x * x + c, t * x * y - s * z, t * x * z + s * y], [t * x * y + s * z, t * y * y + c, t * y * z - s * x], [t * x * z - s * y, t * y * z + s * x, t * z * z + c]]);
}
// Special case rotations
}, {
key: 'RotationX',
value: function RotationX(t) {
var c = Math.cos(t);
var s = Math.sin(t);
return Matrix.create([[1, 0, 0], [0, c, -s], [0, s, c]]);
}
}, {
key: 'RotationY',
value: function RotationY(t) {
var c = Math.cos(t);
var s = Math.sin(t);
return Matrix.create([[c, 0, s], [0, 1, 0], [-s, 0, c]]);
}
}, {
key: 'RotationZ',
value: function RotationZ(t) {
var c = Math.cos(t);
var s = Math.sin(t);
return Matrix.create([[c, -s, 0], [s, c, 0], [0, 0, 1]]);
}
// Random matrix of n rows, m columns
}, {
key: 'Random',
value: function Random(n, m) {
if (arguments.length === 1) {
m = n;
}
return Matrix.Zero(n, m).map(function () {
return Math.random();
});
}
}, {
key: 'Fill',
value: function Fill(n, m, v) {
if (arguments.length === 2) {
v = m;
m = n;
}
var els = [];
var i = n;
var j = void 0;
while (i--) {
j = m;
els[i] = [];
while (j--) {
els[i][j] = v;
}
}
return Matrix.create(els);
}
// Matrix filled with zeros
}, {
key: 'Zero',
value: function Zero(n, m) {
return Matrix.Fill(n, m, 0);
}
// Matrix filled with zeros
}, {
key: 'Zeros',
value: function Zeros(n, m) {
return Matrix.Zero(n, m);
}
// Matrix filled with ones
}, {
key: 'One',
value: function One(n, m) {
return Matrix.Fill(n, m, 1);
}
// Matrix filled with ones
}, {
key: 'Ones',
value: function Ones(n, m) {
return Matrix.One(n, m);
}
}]);
return Matrix;
}();
// otherwise use the slower pure Javascript versions
Matrix.prototype.svd = Matrix.prototype.svdJs;
Matrix.prototype.qr = Matrix.prototype.qrJs;
Matrix.prototype.lu = Matrix.prototype.luJs;