mirror of
https://github.com/josdejong/mathjs.git
synced 2025-12-08 19:46:04 +00:00
144 lines
3.8 KiB
JavaScript
144 lines
3.8 KiB
JavaScript
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Matrix = require('../../type/Matrix.js'),
|
|
|
|
object = util.object,
|
|
array = util.array,
|
|
string = util.string;
|
|
|
|
/**
|
|
* @constructor det
|
|
* Calculate the determinant of a matrix
|
|
*
|
|
* det(x)
|
|
*
|
|
* @param {Array | Matrix} x
|
|
* @return {Number} determinant
|
|
*/
|
|
math.det = function det (x) {
|
|
if (arguments.length != 1) {
|
|
throw new util.error.ArgumentsError('det', arguments.length, 1);
|
|
}
|
|
|
|
var size = array.size(x.valueOf());
|
|
switch (size.length) {
|
|
case 0:
|
|
// scalar
|
|
return object.clone(x);
|
|
break;
|
|
|
|
case 1:
|
|
// vector
|
|
if (size[0] == 1) {
|
|
return object.clone(x.valueOf()[0]);
|
|
}
|
|
else {
|
|
throw new RangeError('Matrix must be square ' +
|
|
'(size: ' + string.format(size) + ')');
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
// two dimensional array
|
|
var rows = size[0];
|
|
var cols = size[1];
|
|
if (rows == cols) {
|
|
return _det(x.valueOf(), rows, cols);
|
|
}
|
|
else {
|
|
throw new RangeError('Matrix must be square ' +
|
|
'(size: ' + string.format(size) + ')');
|
|
}
|
|
break;
|
|
|
|
default:
|
|
// multi dimensional array
|
|
throw new RangeError('Matrix must be two dimensional ' +
|
|
'(size: ' + string.format(size) + ')');
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Calculate the determinant of a matrix
|
|
* @param {Array[]} matrix A square, two dimensional matrix
|
|
* @param {Number} rows Number of rows of the matrix (zero-based)
|
|
* @param {Number} cols Number of columns of the matrix (zero-based)
|
|
* @returns {Number} det
|
|
* @private
|
|
*/
|
|
function _det (matrix, rows, cols) {
|
|
if (rows == 1) {
|
|
// this is a 1 x 1 matrix
|
|
return matrix[0][0];
|
|
}
|
|
else if (rows == 2) {
|
|
// this is a 2 x 2 matrix
|
|
// the determinant of [a11,a12;a21,a22] is det = a11*a22-a21*a12
|
|
return math.subtract(
|
|
math.multiply(matrix[0][0], matrix[1][1]),
|
|
math.multiply(matrix[1][0], matrix[0][1])
|
|
);
|
|
}
|
|
else {
|
|
// this is an n x n matrix
|
|
var d = 1;
|
|
var lead = 0;
|
|
for (var r = 0; r < rows; r++) {
|
|
if (lead >= cols) {
|
|
break;
|
|
}
|
|
var i = r;
|
|
// Find the pivot element.
|
|
while (matrix[i][lead] == 0) {
|
|
i++;
|
|
if (i == rows) {
|
|
i = r;
|
|
lead++;
|
|
if (lead == cols) {
|
|
// We found the last pivot.
|
|
if (object.deepEqual(matrix, eye(rows).valueOf())) {
|
|
return math.round(d, 6);
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (i != r) {
|
|
// Swap rows i and r, which negates the determinant.
|
|
for (var a = 0; a < cols; a++) {
|
|
var temp = matrix[i][a];
|
|
matrix[i][a] = matrix[r][a];
|
|
matrix[r][a] = temp;
|
|
}
|
|
d *= -1;
|
|
}
|
|
// Scale row r and the determinant simultaneously.
|
|
var div = matrix[r][lead];
|
|
for (var a = 0; a < cols; a++) {
|
|
matrix[r][a] = matrix[r][a] / div;
|
|
}
|
|
d *= div;
|
|
// Back-substitute upwards.
|
|
for (var j = 0; j < rows; j++) {
|
|
if (j != r) {
|
|
// Taking linear combinations does not change the det.
|
|
var c = matrix[j][lead];
|
|
for (var a = 0; a < cols; a++) {
|
|
matrix[j][a] = matrix[j][a] - matrix[r][a] * c;
|
|
}
|
|
}
|
|
}
|
|
lead++; // Now looking for a pivot further right.
|
|
}
|
|
// If reduction did not result in the identity, the matrix is singular.
|
|
if (object.deepEqual(matrix, math.eye(rows).valueOf())) {
|
|
return math.round(d, 6);
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
};
|