mathjs/lib/type/Matrix.js
Rogelio J. Baucells cf03b03578 lusolve() - partial
2015-04-08 18:00:42 -04:00

380 lines
13 KiB
JavaScript

'use strict';
var util = require('../util/index');
var string = util.string;
var array = util.array;
var isString = string.isString;
var isArray = Array.isArray;
function factory (type, config, load, typed) {
/**
* @constructor Matrix
*
* A Matrix is a wrapper around an Array. A matrix can hold a multi dimensional
* array. A matrix can be constructed as:
* var matrix = math.matrix(data)
*
* Matrix contains the functions to resize, get and set values, get the size,
* clone the matrix and to convert the matrix to a vector, array, or scalar.
* Furthermore, one can iterate over the matrix using map and forEach.
* The internal Array of the Matrix can be accessed using the function valueOf.
*
* Example usage:
* var matrix = math.matrix([[1, 2], [3, 4]]);
* matix.size(); // [2, 2]
* matrix.resize([3, 2], 5);
* matrix.valueOf(); // [[1, 2], [3, 4], [5, 5]]
* matrix.subset([1,2]) // 3 (indexes are zero-based)
*
*/
function Matrix() {
if (!(this instanceof Matrix)) {
throw new SyntaxError('Constructor must be called with the new operator');
}
}
/**
* Test whether an object is a Matrix
* @param {*} object
* @return {Boolean} isMatrix
*/
Matrix.isMatrix = function (object) {
return (object instanceof Matrix);
};
/**
* Get the Matrix storage constructor for the given format.
*
* @param {string} format The Matrix storage format.
*
* @return {Function} The Matrix storage constructor.
*/
Matrix.storage = function (format) {
// check storage format is a string
if (!isString(format)) {
throw new TypeError('format must be a string value');
}
// get storage format constructor
var constructor = Matrix._storage[format];
if (!constructor) {
throw new SyntaxError('Unsupported matrix storage format: ' + format);
}
// return storage constructor
return constructor;
};
// a map with all constructors for all storage types
Matrix._storage = {};
/**
* Get the storage format used by the matrix.
*
* Usage:
* var format = matrix.storage() // retrieve storage format
*
* @return {string} The storage format.
*/
Matrix.prototype.storage = function () {
// must be implemented by each of the Matrix implementations
throw new Error('Cannot invoke storage on a Matrix interface');
};
/**
* Get a subset of the matrix, or replace a subset of the matrix.
*
* Usage:
* var subset = matrix.subset(index) // retrieve subset
* var value = matrix.subset(index, replacement) // replace subset
*
* @param {Index} index
* @param {Array | Matrix | *} [replacement]
* @param {*} [defaultValue=0] Default value, filled in on new entries when
* the matrix is resized. If not provided,
* new matrix elements will be filled with zeros.
*/
Matrix.prototype.subset = function (index, replacement, defaultValue) {
// must be implemented by each of the Matrix implementations
throw new Error('Cannot invoke subset on a Matrix interface');
};
/**
* Get a single element from the matrix.
* @param {Number[]} index Zero-based index
* @return {*} value
*/
Matrix.prototype.get = function (index) {
// must be implemented by each of the Matrix implementations
throw new Error('Cannot invoke get on a Matrix interface');
};
/**
* Replace a single element in the matrix.
* @param {Number[]} index Zero-based index
* @param {*} value
* @param {*} [defaultValue] Default value, filled in on new entries when
* the matrix is resized. If not provided,
* new matrix elements will be left undefined.
* @return {Matrix} self
*/
Matrix.prototype.set = function (index, value, defaultValue) {
// must be implemented by each of the Matrix implementations
throw new Error('Cannot invoke set on a Matrix interface');
};
/**
* Resize the matrix to the given size. Returns a copy of the matrix when
* `copy=true`, otherwise return the matrix itself (resize in place).
*
* @param {Number[]} size The new size the matrix should have.
* @param {*} [defaultValue=0] Default value, filled in on new entries.
* If not provided, the matrix elements will
* be filled with zeros.
* @param {boolean} [copy] Return a resized copy of the matrix
*
* @return {Matrix} The resized matrix
*/
Matrix.prototype.resize = function (size, defaultValue) {
// must be implemented by each of the Matrix implementations
throw new Error('Cannot invoke resize on a Matrix interface');
};
/**
* Create a clone of the matrix
* @return {Matrix} clone
*/
Matrix.prototype.clone = function () {
// must be implemented by each of the Matrix implementations
throw new Error('Cannot invoke clone on a Matrix interface');
};
/**
* Retrieve the size of the matrix.
* @returns {Number[]} size
*/
Matrix.prototype.size = function() {
// must be implemented by each of the Matrix implementations
throw new Error('Cannot invoke size on a Matrix interface');
};
/**
* Create a new matrix with the results of the callback function executed on
* each entry of the matrix.
* @param {function} callback The callback function is invoked with three
* parameters: the value of the element, the index
* of the element, and the Matrix being traversed.
* @param {boolean} [skipZeros] Invoke callback function for non-zero values only.
*
* @return {Matrix} matrix
*/
Matrix.prototype.map = function (callback, skipZeros) {
// must be implemented by each of the Matrix implementations
throw new Error('Cannot invoke map on a Matrix interface');
};
/**
* Execute a callback function on each entry of the matrix.
* @param {function} callback The callback function is invoked with three
* parameters: the value of the element, the index
* of the element, and the Matrix being traversed.
*/
Matrix.prototype.forEach = function (callback) {
// must be implemented by each of the Matrix implementations
throw new Error('Cannot invoke forEach on a Matrix interface');
};
/**
* Create an Array with a copy of the data of the Matrix
* @returns {Array} array
*/
Matrix.prototype.toArray = function () {
// must be implemented by each of the Matrix implementations
throw new Error('Cannot invoke toArray on a Matrix interface');
};
/**
* Get the primitive value of the Matrix: a multidimensional array
* @returns {Array} array
*/
Matrix.prototype.valueOf = function () {
// must be implemented by each of the Matrix implementations
throw new Error('Cannot invoke valueOf on a Matrix interface');
};
/**
* Get a string representation of the matrix, with optional formatting options.
* @param {Object | Number | Function} [options] Formatting options. See
* lib/util/number:format for a
* description of the available
* options.
* @returns {String} str
*/
Matrix.prototype.format = function (options) {
// must be implemented by each of the Matrix implementations
throw new Error('Cannot invoke format on a Matrix interface');
};
/**
* Get a string representation of the matrix
* @returns {String} str
*/
Matrix.prototype.toString = function () {
// must be implemented by each of the Matrix implementations
throw new Error('Cannot invoke toString on a Matrix interface');
};
/**
* Calculates the transpose of the matrix
* @returns {Matrix}
*/
Matrix.prototype.transpose = function () {
// must be implemented by each of the Matrix implementations
throw new Error('Cannot invoke transpose on a Matrix interface');
};
/**
* Calculate the trace of a matrix: the sum of the elements on the main
* diagonal of a square matrix.
*
* See also:
*
* diagonal
*
* @returns {Number} The matrix trace
*/
Matrix.prototype.trace = function () {
// must be implemented by each of the Matrix implementations
throw new Error('Cannot invoke transpose on a Matrix interface');
};
/**
* Multiply the matrix values times the argument.
*
* @param {Number | BigNumber | Boolean | Complex | Unit | Array | Matrix | null} Value to multiply.
*
* @return {Number | BigNumber | Complex | Unit | Matrix}
*/
Matrix.prototype.multiply = function (value) {
// must be implemented by each of the Matrix implementations
throw new Error('Cannot invoke multiply on a Matrix interface');
};
/**
* LU decomposition with pivoting. Matrix A is decomposed in three matrices (L, U, P) where:
* P * A = L * U
*
* @return {Object with fields L, U and P} The lower triangular matrix, the upper triangular matrix and the permutation matrix.
*/
Matrix.prototype.lup = function (value) {
// must be implemented by each of the Matrix implementations
throw new Error('Cannot invoke lup on a Matrix interface');
};
/**
* Solves the linear equation system by forward substitution. Matrix must be a lower triangular matrix.
*
* M * x = b
*
* @param {Matrix, Array} A column vector with the b values
*
* @return {Matrix} A vector with the linear system solution
*/
Matrix.prototype.forwardSubstitution = function (b) {
// must be implemented by each of the Matrix implementations
throw new Error('Cannot invoke forwardSubstitution on a Matrix interface');
};
/**
* Solves the linear equation system by backward substitution. Matrix must be an upper triangular matrix.
*
* M * x = b
*
* @param {Matrix, Array} A column vector with the b values.
*
* @return {Matrix} A vector with the linear system solution.
*/
Matrix.prototype.backwardSubstitution = function (b) {
// must be implemented by each of the Matrix implementations
throw new Error('Cannot invoke backwardSubstitution on a Matrix interface');
};
/**
* Validates matrix and column vector b for backward/forward substitution algorithms.
*
* @return {Function} Column vector accessor function
*/
Matrix.prototype._substitutionValidation = function (b) {
// validate matrix dimensions
if (this._size.length !== 2)
throw new RangeError('Matrix must be two dimensional (size: ' + string.format(this._size) + ')');
// rows & columns
var rows = this._size[0];
var columns = this._size[1];
// validate rows & columns
if (rows !== columns)
throw new RangeError('Matrix must be square (size: ' + string.format(this._size) + ')');
// check b is matrix
if (b instanceof Matrix) {
// matrix size
var msize = b.size();
// check matrix dimensions, vector
if (msize.length === 1) {
// check vector length
if (msize[0] !== rows)
throw new RangeError('Dimension mismatch. Matrix columns must match vector length.');
// return vector accessor
return function (i) {
return b.get([i]);
};
}
// check matrix dimensions, column vector
if (msize.length === 2) {
// array must be a column vector
if (msize[0] !== rows || msize[1] !== 1)
throw new RangeError('Dimension mismatch. Matrix columns must match vector length.');
// return vector accessor
return function (i) {
return b.get([i, 0]);
};
}
throw new RangeError('Dimension mismatch. Matrix columns must match vector length.');
}
// check b is array
if (isArray(b)) {
// size
var asize = array.size(b);
// check matrix dimensions, vector
if (asize.length === 1) {
// check vector length
if (asize[0] !== rows)
throw new RangeError('Dimension mismatch. Matrix columns must match vector length.');
// return vector accessor
return function (i) {
return b[i];
};
}
// check matrix dimensions, column vector
if (asize.length === 2) {
// array must be a column vector
if (asize[0] !== rows || asize[1] !== 1)
throw new RangeError('Dimension mismatch. Matrix columns must match vector length.');
// return vector accessor
return function (i) {
return b[i][0];
};
}
throw new RangeError('Dimension mismatch. Matrix columns must match vector length.');
}
};
// exports
return Matrix;
}
exports.name = 'Matrix';
exports.path = 'type';
exports.factory = factory;