UNPKG

laplace-determinant

Version:

recursive determinant computation using Laplace expansion

116 lines (95 loc) 2.84 kB
var no = require('not-defined') /** * Convert a pair of indices to a 1-dimensional index * * @function * @param {Number} i index row * @param {Number} j index column * @param {Number} numCols * * @returns {Number} index */ function matrixToArrayIndex (i, j, numCols) { return j + i * numCols } /** * Compute the sub-matrix formed by deleting the i-th row and j-th column * * @function * * @param {Array} data set * @param {Number} numRows * @param {Number} numCols * @param {Number} row index deleted * @param {Number} col index deleted * * @returns {Array} sub data-set */ function subMatrix (data, numRows, numCols, row, col) { var sub = [] for (var i = 0; i < numRows; i++) { for (var j = 0; j < numCols; j++) { if ((i !== row) && (j !== col)) { sub.push(data[matrixToArrayIndex(i, j, numCols)]) } } } return sub } /** * Computes the determinant of a matrix using Laplace's formula * * See https://en.wikipedia.org/wiki/Laplace_expansion * * @function * * @param {Array} data, lenght must be a square. * @param {Object} [scalar] * @param {Function} [scalar.addition = (a, b) -> a + b ] * @param {Function} [scalar.multiplication = (a, b) -> a * b ] * @param {Function} [scalar.negation = (a) -> -a ] * @param {Number} [order], defaults to Math.sqrt(data.length) * * @returns {*} det */ function determinant (data, scalar, order) { // Recursion will stop here: // the determinant of a 1x1 matrix is its only element. if (data.length === 1) return data[0] if (no(order)) order = Math.sqrt(data.length) if (order % 1 !== 0) { throw new TypeError('data.lenght must be a square') } // Default to common real number field. if (no(scalar)) { scalar = { addition: function (a, b) { return a + b }, multiplication: function (a, b) { return a * b }, negation: function (a) { return -a } } } var det // TODO choose best row or column to start from, i.e. the one with more zeros // by now we start from first row, and walk by column // needs scalar.isZero // // is scalar.isZero is a function will be used, but should remain optional var startingRow = 0 for (var col = 0; col < order; col++) { var subData = subMatrix(data, order, order, startingRow, col) // +-- Recursion here. // ↓ var cofactor = determinant(subData, scalar, order - 1) if ((startingRow + col) % 2 === 1) { cofactor = scalar.negation(cofactor) } var index = matrixToArrayIndex(startingRow, col, order) if (no(det)) { det = scalar.multiplication(data[index], cofactor) // first iteration } else { det = scalar.addition(det, scalar.multiplication(data[index], cofactor)) } } return det } module.exports = determinant