mirror of
https://github.com/josdejong/mathjs.git
synced 2026-01-18 14:59:29 +00:00
sync
This commit is contained in:
parent
b2067268be
commit
472299d341
@ -9,37 +9,43 @@ var string = util.string;
|
||||
var number = util.number;
|
||||
|
||||
var isArray = Array.isArray;
|
||||
var isNumber = util.number.isNumber;
|
||||
var isInteger = util.number.isInteger;
|
||||
var isNumber = number.isNumber;
|
||||
var isInteger = number.isInteger;
|
||||
var isString = string.isString;
|
||||
|
||||
var validateIndex = array.validateIndex;
|
||||
|
||||
function factory (type, config, load) {
|
||||
|
||||
var equalScalar = load(require('../../function/relational/equalScalar'));
|
||||
|
||||
var equal = load(require('../../function/relational/equal'));
|
||||
|
||||
var Index = type.Index;
|
||||
var BigNumber = type.BigNumber;
|
||||
var Matrix = type.Matrix;
|
||||
|
||||
function SparseMatrix(data) {
|
||||
/**
|
||||
* Sparse Matrix implementation. This type implements a Compressed Column Storage format
|
||||
* for sparse matrices.
|
||||
*/
|
||||
function SparseMatrix(data, datatype) {
|
||||
if (!(this instanceof SparseMatrix))
|
||||
throw new SyntaxError('Constructor must be called with the new operator');
|
||||
|
||||
if (datatype && !isString(datatype))
|
||||
throw new Error('Invalid datatype: ' + datatype);
|
||||
|
||||
if (data instanceof Matrix) {
|
||||
// create from matrix
|
||||
_createFromMatrix(this, data);
|
||||
_createFromMatrix(this, data, datatype);
|
||||
}
|
||||
else if (data && isArray(data.index) && isArray(data.ptr) && isArray(data.size)) {
|
||||
// initialize fields (values can be undefined in pattern matrices)
|
||||
// initialize fields
|
||||
this._values = data.values;
|
||||
this._index = data.index;
|
||||
this._ptr = data.ptr;
|
||||
this._size = data.size;
|
||||
this._datatype = datatype || data.datatype;
|
||||
}
|
||||
else if (isArray(data)) {
|
||||
// create from array
|
||||
_createFromArray(this, data);
|
||||
_createFromArray(this, data, datatype);
|
||||
}
|
||||
else if (data) {
|
||||
// unsupported type
|
||||
@ -51,10 +57,11 @@ function factory (type, config, load) {
|
||||
this._index = [];
|
||||
this._ptr = [0];
|
||||
this._size = [0];
|
||||
this._datatype = datatype;
|
||||
}
|
||||
}
|
||||
|
||||
var _createFromMatrix = function (matrix, source) {
|
||||
var _createFromMatrix = function (matrix, source, datatype) {
|
||||
// check matrix type
|
||||
if (source.type === 'SparseMatrix') {
|
||||
// clone arrays
|
||||
@ -62,18 +69,20 @@ function factory (type, config, load) {
|
||||
matrix._index = object.clone(source._index);
|
||||
matrix._ptr = object.clone(source._ptr);
|
||||
matrix._size = object.clone(source._size);
|
||||
matrix._datatype = datatype || source._datatype;
|
||||
}
|
||||
else {
|
||||
// build from matrix data
|
||||
_createFromArray(matrix, source.valueOf());
|
||||
_createFromArray(matrix, source.valueOf(), datatype || source._datatype);
|
||||
}
|
||||
};
|
||||
|
||||
var _createFromArray = function (matrix, data) {
|
||||
var _createFromArray = function (matrix, data, datatype) {
|
||||
// initialize fields
|
||||
matrix._values = [];
|
||||
matrix._index = [];
|
||||
matrix._ptr = [];
|
||||
matrix._datatype = datatype;
|
||||
// discover rows & columns, do not use math.size() to avoid looping array twice
|
||||
var rows = data.length;
|
||||
var columns = 0;
|
||||
@ -99,7 +108,7 @@ function factory (type, config, load) {
|
||||
// value
|
||||
var v = row[j];
|
||||
// check value != 0
|
||||
if (!equal(v, 0)) {
|
||||
if (!equalScalar(v, 0)) {
|
||||
// store value
|
||||
matrix._values.push(v);
|
||||
// index
|
||||
@ -112,7 +121,7 @@ function factory (type, config, load) {
|
||||
if (j === 0 && columns < 1)
|
||||
columns = 1;
|
||||
// check value != 0 (row is a scalar)
|
||||
if (!equal(row, 0)) {
|
||||
if (!equalScalar(row, 0)) {
|
||||
// store value
|
||||
matrix._values.push(row);
|
||||
// index
|
||||
@ -131,7 +140,7 @@ function factory (type, config, load) {
|
||||
matrix._size = [rows, columns];
|
||||
};
|
||||
|
||||
SparseMatrix.prototype = new Matrix();
|
||||
SparseMatrix.prototype = new type.Matrix();
|
||||
|
||||
SparseMatrix.prototype.type = 'SparseMatrix';
|
||||
|
||||
@ -146,6 +155,34 @@ function factory (type, config, load) {
|
||||
SparseMatrix.prototype.storage = function () {
|
||||
return 'sparse';
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the datatype of the data stored in the matrix.
|
||||
*
|
||||
* Usage:
|
||||
* var format = matrix.datatype() // retrieve matrix datatype
|
||||
*
|
||||
* @return {string} The datatype.
|
||||
*/
|
||||
SparseMatrix.prototype.datatype = function () {
|
||||
return this._datatype;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the matrix density.
|
||||
*
|
||||
* Usage:
|
||||
* var density = matrix.density() // retrieve matrix density
|
||||
*
|
||||
* @return {number} The matrix density.
|
||||
*/
|
||||
SparseMatrix.prototype.density = function () {
|
||||
// rows & columns
|
||||
var rows = this._size[0];
|
||||
var columns = this._size[1];
|
||||
// calculate density
|
||||
return rows !== 0 && columns !== 0 ? (this._index.length / (rows * columns)) : 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a subset of the matrix, or replace a subset of the matrix.
|
||||
@ -160,7 +197,11 @@ function factory (type, config, load) {
|
||||
* the matrix is resized. If not provided,
|
||||
* new matrix elements will be filled with zeros.
|
||||
*/
|
||||
SparseMatrix.prototype.subset = function (index, replacement, defaultValue) {
|
||||
SparseMatrix.prototype.subset = function (index, replacement, defaultValue) {
|
||||
// check it is a pattern matrix
|
||||
if (!this._values)
|
||||
throw new Error('Cannot invoke subset on a Pattern only matrix');
|
||||
|
||||
// check arguments
|
||||
switch (arguments.length) {
|
||||
case 1:
|
||||
@ -178,7 +219,7 @@ function factory (type, config, load) {
|
||||
|
||||
var _getsubset = function (matrix, index) {
|
||||
// check index
|
||||
if (!(index instanceof Index)) {
|
||||
if (!(index instanceof type.Index)) {
|
||||
throw new TypeError('Invalid index');
|
||||
}
|
||||
|
||||
@ -212,7 +253,7 @@ function factory (type, config, load) {
|
||||
|
||||
var _setsubset = function (matrix, index, submatrix, defaultValue) {
|
||||
// check index
|
||||
if (!(index instanceof Index)) {
|
||||
if (!(index instanceof type.Index)) {
|
||||
throw new TypeError('Invalid index');
|
||||
}
|
||||
|
||||
@ -222,7 +263,7 @@ function factory (type, config, load) {
|
||||
|
||||
// calculate the size of the submatrix, and convert it into an Array if needed
|
||||
var sSize;
|
||||
if (submatrix instanceof Matrix) {
|
||||
if (submatrix instanceof type.Matrix) {
|
||||
// submatrix size
|
||||
sSize = submatrix.size();
|
||||
// use array representation
|
||||
@ -302,6 +343,10 @@ function factory (type, config, load) {
|
||||
if (index.length != this._size.length)
|
||||
throw new DimensionError(index.length, this._size.length);
|
||||
|
||||
// check it is a pattern matrix
|
||||
if (!this._values)
|
||||
throw new Error('Cannot invoke get on a Pattern only matrix');
|
||||
|
||||
// row and column
|
||||
var i = index[0];
|
||||
var j = index[1];
|
||||
@ -334,6 +379,10 @@ function factory (type, config, load) {
|
||||
if (index.length != this._size.length)
|
||||
throw new DimensionError(index.length, this._size.length);
|
||||
|
||||
// check it is a pattern matrix
|
||||
if (!this._values)
|
||||
throw new Error('Cannot invoke set on a Pattern only matrix');
|
||||
|
||||
// row and column
|
||||
var i = index[0];
|
||||
var j = index[1];
|
||||
@ -360,7 +409,7 @@ function factory (type, config, load) {
|
||||
// check k is prior to next column k and it is in the correct row
|
||||
if (k < this._ptr[j + 1] && this._index[k] === i) {
|
||||
// check value != 0
|
||||
if (!equal(v, 0)) {
|
||||
if (!equalScalar(v, 0)) {
|
||||
// update value
|
||||
this._values[k] = v;
|
||||
}
|
||||
@ -454,7 +503,7 @@ function factory (type, config, load) {
|
||||
// value to insert at the time of growing matrix
|
||||
var value = defaultValue || 0;
|
||||
// should we insert the value?
|
||||
var ins = !equal(value, 0);
|
||||
var ins = !equalScalar(value, 0);
|
||||
|
||||
// old columns and rows
|
||||
var r = matrix._size[0];
|
||||
@ -561,10 +610,11 @@ function factory (type, config, load) {
|
||||
*/
|
||||
SparseMatrix.prototype.clone = function () {
|
||||
var m = new SparseMatrix({
|
||||
values: object.clone(this._values),
|
||||
values: this._values ? object.clone(this._values) : undefined,
|
||||
index: object.clone(this._index),
|
||||
ptr: object.clone(this._ptr),
|
||||
size: object.clone(this._size)
|
||||
size: object.clone(this._size),
|
||||
datatype: this._datatype
|
||||
});
|
||||
return m;
|
||||
};
|
||||
@ -588,6 +638,9 @@ function factory (type, config, load) {
|
||||
* @return {SparseMatrix} matrix
|
||||
*/
|
||||
SparseMatrix.prototype.map = function (callback, skipZeros) {
|
||||
// check it is a pattern matrix
|
||||
if (!this._values)
|
||||
throw new Error('Cannot invoke map on a Pattern only matrix');
|
||||
// matrix instance
|
||||
var me = this;
|
||||
// rows and columns
|
||||
@ -616,7 +669,7 @@ function factory (type, config, load) {
|
||||
// invoke callback
|
||||
v = callback(v, x, y);
|
||||
// check value != 0
|
||||
if (!equal(v, 0)) {
|
||||
if (!equalScalar(v, 0)) {
|
||||
// store value
|
||||
values.push(v);
|
||||
// index
|
||||
@ -674,6 +727,9 @@ function factory (type, config, load) {
|
||||
* @param {boolean} [skipZeros] Invoke callback function for non-zero values only.
|
||||
*/
|
||||
SparseMatrix.prototype.forEach = function (callback, skipZeros) {
|
||||
// check it is a pattern matrix
|
||||
if (!this._values)
|
||||
throw new Error('Cannot invoke forEach on a Pattern only matrix');
|
||||
// matrix instance
|
||||
var me = this;
|
||||
// rows and columns
|
||||
@ -732,31 +788,27 @@ function factory (type, config, load) {
|
||||
var columns = size[1];
|
||||
// result
|
||||
var a = new Array(rows);
|
||||
// vars
|
||||
var i, j;
|
||||
// initialize array
|
||||
for (var q = 0; q < rows; q++)
|
||||
a[q] = new Array(columns);
|
||||
for (i = 0; i < rows; i++) {
|
||||
a[i] = new Array(columns);
|
||||
for (j = 0; j < columns; j++)
|
||||
a[i][j] = 0;
|
||||
}
|
||||
|
||||
// loop columns
|
||||
for (var j = 0; j < columns; j++) {
|
||||
for (j = 0; j < columns; j++) {
|
||||
// k0 <= k < k1 where k0 = _ptr[j] && k1 = _ptr[j+1]
|
||||
var k0 = ptr[j];
|
||||
var k1 = ptr[j + 1];
|
||||
// row pointer
|
||||
var p = 0;
|
||||
// loop k within [k0, k1[
|
||||
for (var k = k0; k < k1; k++) {
|
||||
// row index
|
||||
var i = index[k];
|
||||
// zeros
|
||||
for (var x = p; x < i; x++)
|
||||
a[x][j] = a[x][j] || 0;
|
||||
// set value, check it is a pattern matrix
|
||||
i = index[k];
|
||||
// set value (use one for pattern matrix)
|
||||
a[i][j] = values ? (copy ? object.clone(values[k]) : values[k]) : 1;
|
||||
// update pointer
|
||||
p = i + 1;
|
||||
}
|
||||
// zero values
|
||||
for (var y = p; y < rows; y++)
|
||||
a[y][j] = a[y][j] || 0;
|
||||
}
|
||||
return a;
|
||||
};
|
||||
@ -773,8 +825,10 @@ function factory (type, config, load) {
|
||||
// rows and columns
|
||||
var rows = this._size[0];
|
||||
var columns = this._size[1];
|
||||
// density
|
||||
var density = this.density();
|
||||
// rows & columns
|
||||
var str = 'Sparse Matrix [' + string.format(rows, options) + ' x ' + string.format(columns, options) + '] density: ' + string.format(this._values.length / (rows * columns), options) + '\n';
|
||||
var str = 'Sparse Matrix [' + string.format(rows, options) + ' x ' + string.format(columns, options) + '] density: ' + string.format(density, options) + '\n';
|
||||
// loop columns
|
||||
for (var j = 0; j < columns; j++) {
|
||||
// k0 <= k < k1 where k0 = _ptr[j] && k1 = _ptr[j+1]
|
||||
@ -785,7 +839,7 @@ function factory (type, config, load) {
|
||||
// row index
|
||||
var i = this._index[k];
|
||||
// append value
|
||||
str += '\n (' + string.format(i, options) + ', ' + string.format(j, options) + ') ==> ' + string.format(this._values[k], options);
|
||||
str += '\n (' + string.format(i, options) + ', ' + string.format(j, options) + ') ==> ' + (this._values ? string.format(this._values[k], options) : 'X');
|
||||
}
|
||||
}
|
||||
return str;
|
||||
@ -809,7 +863,8 @@ function factory (type, config, load) {
|
||||
values: this._values,
|
||||
index: this._index,
|
||||
ptr: this._ptr,
|
||||
size: this._size
|
||||
size: this._size,
|
||||
datatype: this._datatype
|
||||
};
|
||||
};
|
||||
|
||||
@ -824,7 +879,7 @@ function factory (type, config, load) {
|
||||
// validate k if any
|
||||
if (k) {
|
||||
// convert BigNumber to a number
|
||||
if (k instanceof BigNumber)
|
||||
if (k instanceof type.BigNumber)
|
||||
k = k.toNumber();
|
||||
// is must be an integer
|
||||
if (!isNumber(k) || !isInteger(k)) {
|
||||
@ -912,7 +967,7 @@ function factory (type, config, load) {
|
||||
// map size & validate
|
||||
size = size.map(function (s) {
|
||||
// check it is a big number
|
||||
if (s instanceof BigNumber) {
|
||||
if (s instanceof type.BigNumber) {
|
||||
// convert it
|
||||
s = s.toNumber();
|
||||
}
|
||||
@ -926,7 +981,7 @@ function factory (type, config, load) {
|
||||
// validate k if any
|
||||
if (k) {
|
||||
// convert BigNumber to a number
|
||||
if (k instanceof BigNumber)
|
||||
if (k instanceof type.BigNumber)
|
||||
k = k.toNumber();
|
||||
// is must be an integer
|
||||
if (!isNumber(k) || !isInteger(k)) {
|
||||
@ -964,7 +1019,7 @@ function factory (type, config, load) {
|
||||
return value[i];
|
||||
};
|
||||
}
|
||||
else if (value instanceof Matrix) {
|
||||
else if (value instanceof type.Matrix) {
|
||||
// matrix size
|
||||
var ms = value.size();
|
||||
// validate matrix
|
||||
@ -1002,7 +1057,7 @@ function factory (type, config, load) {
|
||||
// get value @ i
|
||||
var v = _value(i);
|
||||
// check for zero
|
||||
if (!equal(v, 0)) {
|
||||
if (!equalScalar(v, 0)) {
|
||||
// column
|
||||
index.push(i + kSub);
|
||||
// add value
|
||||
@ -1090,42 +1145,48 @@ function factory (type, config, load) {
|
||||
var ky = _getValueIndex(y, k0, k1, index);
|
||||
// check both rows exist in matrix
|
||||
if (kx < k1 && ky < k1 && index[kx] === x && index[ky] === y) {
|
||||
// swap values
|
||||
var v = values[kx];
|
||||
values[kx] = values[ky];
|
||||
values[ky] = v;
|
||||
// swap values (check for pattern matrix)
|
||||
if (values) {
|
||||
var v = values[kx];
|
||||
values[kx] = values[ky];
|
||||
values[ky] = v;
|
||||
}
|
||||
// next column
|
||||
continue;
|
||||
}
|
||||
// check x row exist & no y row
|
||||
if (kx < k1 && index[kx] === x && (ky >= k1 || index[ky] !== y)) {
|
||||
// value @ x
|
||||
var vx = values[kx];
|
||||
// value @ x (check for pattern matrix)
|
||||
var vx = values ? values[kx] : undefined;
|
||||
// insert value @ y
|
||||
values.splice(ky, 0, vx);
|
||||
index.splice(ky, 0, y);
|
||||
if (values)
|
||||
values.splice(ky, 0, vx);
|
||||
// remove value @ x (adjust array index if needed)
|
||||
values.splice(ky <= kx ? kx + 1 : kx, 1);
|
||||
index.splice(ky <= kx ? kx + 1 : kx, 1);
|
||||
if (values)
|
||||
values.splice(ky <= kx ? kx + 1 : kx, 1);
|
||||
// next column
|
||||
continue;
|
||||
}
|
||||
// check y row exist & no x row
|
||||
if (ky < k1 && index[ky] === y && (kx >= k1 || index[kx] !== x)) {
|
||||
// value @ y
|
||||
var vy = values[ky];
|
||||
// value @ y (check for pattern matrix)
|
||||
var vy = values ? values[ky] : undefined;
|
||||
// insert value @ x
|
||||
values.splice(kx, 0, vy);
|
||||
index.splice(kx, 0, x);
|
||||
if (values)
|
||||
values.splice(kx, 0, vy);
|
||||
// remove value @ y (adjust array index if needed)
|
||||
values.splice(kx <= ky ? ky + 1 : ky, 1);
|
||||
index.splice(kx <= ky ? ky + 1 : ky, 1);
|
||||
if (values)
|
||||
values.splice(kx <= ky ? ky + 1 : ky, 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// register this type in the base class Matrix
|
||||
Matrix._storage.sparse = SparseMatrix;
|
||||
type.Matrix._storage.sparse = SparseMatrix;
|
||||
|
||||
return SparseMatrix;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user