UNPKG

matrix-inverse

Version:
202 lines (189 loc) 5.03 kB
var Sylvester = {} Sylvester.Matrix = function () {} Sylvester.Matrix.create = function (elements) { var M = new Sylvester.Matrix() return M.setElements(elements) } Sylvester.Matrix.I = function (n) { var els = [], i = n, j while (i--) { j = n els[i] = [] while (j--) { els[i][j] = i === j ? 1 : 0 } } return Sylvester.Matrix.create(els) } Sylvester.Matrix.prototype = { dup: function () { return Sylvester.Matrix.create(this.elements) }, isSquare: function () { var cols = this.elements.length === 0 ? 0 : this.elements[0].length return this.elements.length === cols }, toRightTriangular: function () { if (this.elements.length === 0) return Sylvester.Matrix.create([]) var M = this.dup(), els var n = this.elements.length, i, j, np = this.elements[0].length, p 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 }, determinant: function () { if (this.elements.length === 0) { return 1 } if (!this.isSquare()) { return null } var M = this.toRightTriangular() var det = M.elements[0][0], n = M.elements.length for (var i = 1; i < n; i++) { det = det * M.elements[i][i] } return det }, isSingular: function () { return this.isSquare() && this.determinant() === 0 }, augment: function (matrix) { if (this.elements.length === 0) { return this.dup() } var M = matrix.elements || matrix if (typeof M[0][0] === 'undefined') { M = Sylvester.Matrix.create(M).elements } var T = this.dup(), cols = T.elements[0].length var i = T.elements.length, nj = M[0].length, j if (i !== M.length) { return null } while (i--) { j = nj while (j--) { T.elements[i][cols + j] = M[i][j] } } return T }, inverse: function () { if (this.elements.length === 0) { return null } if (!this.isSquare() || this.isSingular()) { return null } var n = this.elements.length, i = n, j var M = this.augment(Sylvester.Matrix.I(n)).toRightTriangular() var np = M.elements[0].length, p, els, divisor var inverse_elements = [], new_element // Sylvester.Matrix is non-singular so there will be no zeros on the // diagonal. Cycle through rows from last to first. while (i--) { // First, normalise diagonal elements to 1 els = [] inverse_elements[i] = [] divisor = M.elements[i][i] for (p = 0; p < np; p++) { new_element = M.elements[i][p] / divisor els.push(new_element) // 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) { inverse_elements[i].push(new_element) } } 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 Sylvester.Matrix.create(inverse_elements) }, setElements: function (els) { var i, j, elements = els.elements || els if (elements[0] && 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 }, } module.exports = function (elements) { const mat = Sylvester.Matrix.create(elements).inverse() if (mat !== null) { return mat.elements } else { return null } }