mirror of
https://github.com/josdejong/mathjs.git
synced 2026-01-18 14:59:29 +00:00
294 lines
9.1 KiB
JavaScript
294 lines
9.1 KiB
JavaScript
'use strict';
|
|
|
|
var util = require('../util/index');
|
|
var DimensionError = require('../error/DimensionError');
|
|
|
|
var Index = require('./Index');
|
|
|
|
var string = util.string;
|
|
var array = util.array;
|
|
var object = util.object;
|
|
|
|
var isArray = Array.isArray;
|
|
var validateIndex = array.validateIndex;
|
|
var isString = string.isString;
|
|
|
|
module.exports = function (config) {
|
|
|
|
/**
|
|
* @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 = new 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 = new 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)
|
|
*
|
|
* @param {Array | Matrix} [data] A multi dimensional array
|
|
* @param {string} [format] The Matrix storage format, defaults to 'dense'
|
|
*/
|
|
function Matrix(data, format) {
|
|
if (!(this instanceof Matrix)) {
|
|
throw new SyntaxError('Constructor must be called with the new operator');
|
|
}
|
|
|
|
if (data instanceof Matrix) {
|
|
// check we need to change storage format
|
|
if (!format || format === data._storage.format()) {
|
|
// clone storage
|
|
this._storage = data._storage.clone();
|
|
}
|
|
else {
|
|
// change storage format, TODO: find a better solution
|
|
this._storage = _createStorage(data._storage.toArray(), format);
|
|
}
|
|
}
|
|
else if (isArray(data)) {
|
|
// create storage
|
|
this._storage = _createStorage(data, format);
|
|
}
|
|
else if (typeof data === 'object' && data.mathjs === 'Matrix' && data.storage) {
|
|
// create Matrix from json representation
|
|
this._storage = _createStorage(data.storage);
|
|
}
|
|
else if (data != null) {
|
|
// unsupported type
|
|
throw new TypeError('Unsupported type of data (' + util.types.type(data) + ')');
|
|
}
|
|
else {
|
|
// create storage
|
|
this._storage = _createStorage([], format);
|
|
}
|
|
}
|
|
|
|
var _createStorage = function (data, format) {
|
|
// check data is an array
|
|
if (isArray(data)) {
|
|
// format to use
|
|
format = format || 'default';
|
|
// check format
|
|
if (!isString(format))
|
|
throw new TypeError('format must be a string value');
|
|
// get format constructor
|
|
var f = Matrix.format[format];
|
|
if (!f)
|
|
throw new SyntaxError('Unsupported Matrix Storage Format: ' + format);
|
|
// create instance
|
|
return new f(data);
|
|
}
|
|
// check it is a storage json representation
|
|
if (typeof data === 'object' && isString(data.format)) {
|
|
// get format constructor
|
|
var f = Matrix.format[data.format];
|
|
if (!f)
|
|
throw new SyntaxError('Unsupported Matrix Storage Format: ' + data.format);
|
|
// deserialize json
|
|
return f.fromJSON(data);
|
|
}
|
|
throw new SyntaxError('Unsupported data structure');
|
|
};
|
|
|
|
/**
|
|
* Test whether an object is a Matrix
|
|
* @param {*} object
|
|
* @return {Boolean} isMatrix
|
|
*/
|
|
Matrix.isMatrix = function (object) {
|
|
return (object instanceof Matrix);
|
|
};
|
|
|
|
/**
|
|
* 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) {
|
|
if (arguments.length < 1 || arguments.length > 3)
|
|
throw new SyntaxError('Wrong number of arguments');
|
|
|
|
// delegate to storage implementation
|
|
var result = this._storage.subset(index, replacement, defaultValue);
|
|
// check we need to wrap result in a Matrix
|
|
if (result instanceof this._storage.constructor) {
|
|
return new Matrix({
|
|
mathjs: 'Matrix',
|
|
storage: result.toJSON()
|
|
});
|
|
}
|
|
return result;
|
|
};
|
|
|
|
/**
|
|
* Get a single element from the matrix.
|
|
* @param {Number[]} index Zero-based index
|
|
* @return {*} value
|
|
*/
|
|
Matrix.prototype.get = function (index) {
|
|
// delegate to storage implementation
|
|
return this._storage.get(index);
|
|
};
|
|
|
|
/**
|
|
* 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) {
|
|
// delegate to storage implementation
|
|
this._storage.set(index, value, defaultValue);
|
|
|
|
// return the matrix itself
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Resize the matrix
|
|
* @param {Number[]} size
|
|
* @param {*} [defaultValue=0] Default value, filled in on new entries.
|
|
* If not provided, the matrix elements will
|
|
* be filled with zeros.
|
|
* @return {Matrix} self The matrix itself is returned
|
|
*/
|
|
Matrix.prototype.resize = function (size, defaultValue) {
|
|
// delegate to storage implementation
|
|
this._storage.resize(size, defaultValue);
|
|
|
|
// return the matrix itself
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Create a clone of the matrix
|
|
* @return {Matrix} clone
|
|
*/
|
|
Matrix.prototype.clone = function () {
|
|
return new Matrix(this);
|
|
};
|
|
|
|
/**
|
|
* Retrieve the size of the matrix.
|
|
* @returns {Number[]} size
|
|
*/
|
|
Matrix.prototype.size = function() {
|
|
// delegate to storage implementation
|
|
return this._storage.size();
|
|
};
|
|
|
|
/**
|
|
* 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.
|
|
* @return {Matrix} matrix
|
|
*/
|
|
Matrix.prototype.map = function (callback) {
|
|
// current instance
|
|
var me = this;
|
|
// create matrix from storage map
|
|
return new Matrix({
|
|
mathjs: 'Matrix',
|
|
storage: this._storage.map(callback, me).toJSON()
|
|
});
|
|
};
|
|
|
|
/**
|
|
* 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) {
|
|
// current instance
|
|
var me = this;
|
|
// delegate to storage implementation
|
|
this._storage.forEach(callback, me);
|
|
};
|
|
|
|
/**
|
|
* Create an Array with a copy of the data of the Matrix
|
|
* @returns {Array} array
|
|
*/
|
|
Matrix.prototype.toArray = function () {
|
|
// delegate to storage implementation
|
|
return this._storage.toArray();
|
|
};
|
|
|
|
/**
|
|
* Get the primitive value of the Matrix: a multidimensional array
|
|
* @returns {Array} array
|
|
*/
|
|
Matrix.prototype.valueOf = function () {
|
|
// delegate to storage implementation
|
|
return this._storage.valueOf();
|
|
};
|
|
|
|
/**
|
|
* 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) {
|
|
// TODO: find better implementation for sparse matrix formats
|
|
return string.format(this._storage.toArray(), options);
|
|
};
|
|
|
|
/**
|
|
* Get a string representation of the matrix
|
|
* @returns {String} str
|
|
*/
|
|
Matrix.prototype.toString = function () {
|
|
// delegate to storage implementation
|
|
return this._storage.toString();
|
|
};
|
|
|
|
/**
|
|
* Get a JSON representation of the matrix
|
|
* @returns {Object}
|
|
*/
|
|
Matrix.prototype.toJSON = function () {
|
|
return {
|
|
mathjs: 'Matrix',
|
|
storage: this._storage.toJSON()
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Generate a matrix from a JSON object
|
|
* @param {Object} json An object structured like
|
|
* `{"mathjs": "Matrix", data: []}`,
|
|
* where mathjs is optional
|
|
* @returns {Matrix}
|
|
*/
|
|
Matrix.fromJSON = function (json) {
|
|
return new Matrix(json);
|
|
};
|
|
|
|
// exports
|
|
return Matrix;
|
|
}; |