diff --git a/lib/expression/docs/function/construction/matrix.js b/lib/expression/docs/function/construction/matrix.js index cc3115ebc..870391982 100644 --- a/lib/expression/docs/function/construction/matrix.js +++ b/lib/expression/docs/function/construction/matrix.js @@ -5,6 +5,7 @@ module.exports = { '[]', '[a1, b1, ...; a2, b2, ...]', 'matrix()', + 'matrix("dense")', 'matrix([...])' ], 'description': @@ -14,9 +15,11 @@ module.exports = { '[1, 2, 3]', '[1, 2, 3; 4, 5, 6]', 'matrix()', - 'matrix([3, 4])' + 'matrix([3, 4])', + 'matrix([3, 4; 5, 6], "sparse")', + 'matrix([3, 4; 5, 6], "sparse", "number")' ], 'seealso': [ - 'bignumber', 'boolean', 'complex', 'index', 'number', 'string', 'unit' + 'bignumber', 'boolean', 'complex', 'index', 'number', 'string', 'unit', 'sparse' ] }; diff --git a/lib/expression/docs/function/construction/sparse.js b/lib/expression/docs/function/construction/sparse.js new file mode 100644 index 000000000..aaa991a2c --- /dev/null +++ b/lib/expression/docs/function/construction/sparse.js @@ -0,0 +1,19 @@ +module.exports = { + 'name': 'sparse', + 'category': 'Type', + 'syntax': [ + 'sparse()', + 'sparse([a1, b1, ...; a1, b2, ...])', + 'sparse([a1, b1, ...; a1, b2, ...], "number")' + ], + 'description': + 'Create a sparse matrix.', + 'examples': [ + 'sparse()', + 'sparse([3, 4; 5, 6])', + 'sparse([3, 0; 5, 0], "number")' + ], + 'seealso': [ + 'bignumber', 'boolean', 'complex', 'index', 'number', 'string', 'unit', 'matrix' + ] +}; diff --git a/lib/expression/docs/index.js b/lib/expression/docs/index.js index 58761e52c..c3b1dca3e 100644 --- a/lib/expression/docs/index.js +++ b/lib/expression/docs/index.js @@ -75,6 +75,7 @@ function factory (type, config, load, typed) { docs.index = require('./function/construction/index'); docs.matrix = require('./function/construction/matrix'); docs.number = require('./function/construction/number'); + docs.sparse = require('./function/construction/sparse'); docs.string = require('./function/construction/string'); docs.unit = require('./function/construction/unit'); diff --git a/lib/expression/node/BlockNode.js b/lib/expression/node/BlockNode.js index 3b50048d4..070ab637b 100644 --- a/lib/expression/node/BlockNode.js +++ b/lib/expression/node/BlockNode.js @@ -130,7 +130,7 @@ function factory (type, config, load, typed) { BlockNode.prototype._toTex = function (callbacks) { return this.blocks.map(function (param) { return param.node.toTex(callbacks) + (param.visible ? '' : ';'); - }).join('\n'); + }).join('\\;\\;\n'); }; return BlockNode; diff --git a/lib/function/algebra/decomposition/lup.js b/lib/function/algebra/decomposition/lup.js index 2d91ec613..f7b0ce31a 100644 --- a/lib/function/algebra/decomposition/lup.js +++ b/lib/function/algebra/decomposition/lup.js @@ -13,7 +13,7 @@ function factory (type, config, load, typed) { var multiply = load(require('../../arithmetic/multiply')); var subtract = load(require('../../arithmetic/subtract')); var larger = load(require('../../relational/larger')); - var equal = load(require('../../relational/equal')); + var equalScalar = load(require('../../relational/equalScalar')); var unaryMinus = load(require('../../arithmetic/unaryMinus')); var SparseMatrix = type.SparseMatrix; @@ -121,7 +121,7 @@ function factory (type, config, load, typed) { for (i = j + 1; i < rows; i++) { // value @ i, j var vij = data[i][j]; - if (!equal(vij, 0)) { + if (!equalScalar(vij, 0)) { // update data data[i][j] = divideScalar(data[i][j], vjj); } @@ -231,8 +231,8 @@ function factory (type, config, load, typed) { // vars var i, j, k; // permutation vectors, (current index -> original index) and (original index -> current index) - var pv_co = new Array(rows); - var pv_oc = new Array(rows); + var pv_co = []; + var pv_oc = []; for (i = 0; i < rows; i++) { pv_co[i] = i; pv_oc[i] = i; @@ -252,7 +252,7 @@ function factory (type, config, load, typed) { // loop columns for (j = 0; j < columns; j++) { // sparse accumulator - var spa = new Spa(rows); + var spa = new Spa(); // check lower triangular matrix has a value @ column j if (j < rows) { // update ptr @@ -328,7 +328,7 @@ function factory (type, config, load, typed) { // update value v = divideScalar(v, vjj); // check value is non zero - if (!equal(v, 0)) { + if (!equalScalar(v, 0)) { // update lower triangular matrix lvalues.push(v); lindex.push(x); diff --git a/lib/function/algebra/solver/backwardSubstitution.js b/lib/function/algebra/solver/backwardSubstitution.js index 7aabe290d..d387e64c4 100644 --- a/lib/function/algebra/solver/backwardSubstitution.js +++ b/lib/function/algebra/solver/backwardSubstitution.js @@ -6,7 +6,7 @@ function factory (type, config, load, typed) { var divideScalar = load(require('../../arithmetic/divideScalar')); var multiply = load(require('../../arithmetic/multiply')); var subtract = load(require('../../arithmetic/subtract')); - var equal = load(require('../../relational/equal')); + var equalScalar = load(require('../../relational/equalScalar')); var substitutionValidation = load(require('./substitutionValidation')); @@ -50,7 +50,7 @@ function factory (type, config, load, typed) { var rows = m._size[0]; var columns = m._size[1]; // result - var x = new Array(rows); + var x = []; // arrays var data = m._data; // backward solve m * x = b, loop columns (backwards) @@ -60,11 +60,11 @@ function factory (type, config, load, typed) { // x[j] var xj; // backward substitution (outer product) avoids inner looping when bj == 0 - if (!equal(bj, 0)) { + if (!equalScalar(bj, 0)) { // value @ [j, j] var vjj = data[j][j]; // check vjj - if (equal(vjj, 0)) { + if (equalScalar(vjj, 0)) { // system cannot be solved throw new Error('Linear system cannot be solved since matrix is singular'); } @@ -113,7 +113,7 @@ function factory (type, config, load, typed) { // b[j] var bj = b[j] || 0; // backward substitution (outer product) avoids inner looping when bj == 0 - if (!equal(bj, 0)) { + if (!equalScalar(bj, 0)) { // value @ [j, j] var vjj = 0; // first & last indeces in column @@ -134,7 +134,7 @@ function factory (type, config, load, typed) { } } // at this point we must have a value @ [j, j] - if (equal(vjj, 0)) { + if (equalScalar(vjj, 0)) { // system cannot be solved, there is no value @ [j, j] throw new Error('Linear system cannot be solved since matrix is singular'); } @@ -148,7 +148,7 @@ function factory (type, config, load, typed) { b[i] = subtract(b[i] || 0, multiply(xj, values[k])); } // check for non zero - if (!equal(xj, 0)) { + if (!equalScalar(xj, 0)) { // push to values (at the beginning since we are looping backwards) xvalues.unshift(xj); // row diff --git a/lib/function/algebra/solver/forwardSubstitution.js b/lib/function/algebra/solver/forwardSubstitution.js index 99461d5e0..87633b87c 100644 --- a/lib/function/algebra/solver/forwardSubstitution.js +++ b/lib/function/algebra/solver/forwardSubstitution.js @@ -6,7 +6,7 @@ function factory (type, config, load, typed) { var divideScalar = load(require('../../arithmetic/divideScalar')); var multiply = load(require('../../arithmetic/multiply')); var subtract = load(require('../../arithmetic/subtract')); - var equal = load(require('../../relational/equal')); + var equalScalar = load(require('../../relational/equalScalar')); var substitutionValidation = load(require('./substitutionValidation')); @@ -50,7 +50,7 @@ function factory (type, config, load, typed) { var rows = m._size[0]; var columns = m._size[1]; // result - var x = new Array(rows); + var x = []; // data var data = m._data; // forward solve m * x = b, loop columns @@ -60,11 +60,11 @@ function factory (type, config, load, typed) { // x[j] var xj; // forward substitution (outer product) avoids inner looping when bj == 0 - if (!equal(bj, 0)) { + if (!equalScalar(bj, 0)) { // value @ [j, j] var vjj = data[j][j]; // check vjj - if (equal(vjj, 0)) { + if (equalScalar(vjj, 0)) { // system cannot be solved throw new Error('Linear system cannot be solved since matrix is singular'); } @@ -113,7 +113,7 @@ function factory (type, config, load, typed) { // b[j] var bj = b[j] || 0; // forward substitution (outer product) avoids inner looping when bj == 0 - if (!equal(bj, 0)) { + if (!equalScalar(bj, 0)) { // value @ [j, j] var vjj = 0; // last index in column @@ -133,7 +133,7 @@ function factory (type, config, load, typed) { } } // at this point we must have a value @ [j, j] - if (equal(vjj, 0)) { + if (equalScalar(vjj, 0)) { // system cannot be solved, there is no value @ [j, j] throw new Error('Linear system cannot be solved since matrix is singular'); } @@ -147,7 +147,7 @@ function factory (type, config, load, typed) { b[i] = subtract(b[i] || 0, multiply(xj, values[k])); } // check for non zero - if (!equal(xj, 0)) { + if (!equalScalar(xj, 0)) { // value @ row i xvalues.push(xj); // row diff --git a/lib/function/algebra/solver/substitutionValidation.js b/lib/function/algebra/solver/substitutionValidation.js index 95014ff5a..fc1fc4441 100644 --- a/lib/function/algebra/solver/substitutionValidation.js +++ b/lib/function/algebra/solver/substitutionValidation.js @@ -8,7 +8,7 @@ var object = util.object; var isArray = Array.isArray; -function factory (type, config, load, typed) { +function factory (type) { var Matrix = type.Matrix; @@ -52,7 +52,7 @@ function factory (type, config, load, typed) { throw new RangeError('Dimension mismatch. Matrix columns must match vector length.'); } // dense copy of column vector - var x = new Array(rows); + var x = []; // copy values (skip zeros) b.forEach(function (v, index) { x[index[0]] = object.clone(v); diff --git a/lib/function/arithmetic/add.js b/lib/function/arithmetic/add.js index dc381588c..a096a9db8 100644 --- a/lib/function/arithmetic/add.js +++ b/lib/function/arithmetic/add.js @@ -1,7 +1,15 @@ 'use strict'; function factory (type, config, load, typed) { - var collection = load(require('../../type/collection')); + + var matrix = load(require('../construction/matrix')); + var addScalar = load(require('./addScalar')); + + var algorithm01 = load(require('../../type/matrix/util/algorithm01')); + var algorithm04 = load(require('../../type/matrix/util/algorithm04')); + var algorithm10 = load(require('../../type/matrix/util/algorithm10')); + var algorithm13 = load(require('../../type/matrix/util/algorithm13')); + var algorithm14 = load(require('../../type/matrix/util/algorithm14')); /** * Add two values, `x + y`. @@ -34,45 +42,99 @@ function factory (type, config, load, typed) { * @return {Number | BigNumber | Complex | Unit | String | Array | Matrix} Sum of `x` and `y` */ var add = typed('add', { - 'number, number': function (x, y) { - return x + y; + + 'any, any': addScalar, + + 'Matrix, Matrix': function (x, y) { + // result + var c; + + // process matrix storage + switch (x.storage()) { + case 'sparse': + switch (y.storage()) { + case 'sparse': + // sparse + sparse + c = algorithm04(x, y, addScalar); + break; + default: + // sparse + dense + c = algorithm01(y, x, addScalar, true); + break; + } + break; + default: + switch (y.storage()) { + case 'sparse': + // dense + sparse + c = algorithm01(x, y, addScalar, false); + break; + default: + // dense + dense + c = algorithm13(x, y, addScalar); + break; + } + break; + } + return c; + }, + + 'Array, Array': function (x, y) { + // use matrix implementation + return add(matrix(x), matrix(y)).valueOf(); + }, + + 'Array, Matrix': function (x, y) { + // use matrix implementation + return add(matrix(x), y); + }, + + 'Matrix, Array': function (x, y) { + // use matrix implementation + return add(x, matrix(y)); + }, + + 'Matrix, any': function (x, y) { + // result + var c; + // check storage format + switch (x.storage()) { + case 'sparse': + c = algorithm10(x, y, addScalar, false); + break; + default: + c = algorithm14(x, y, addScalar, false); + break; + } + return c; + }, + + 'any, Matrix': function (x, y) { + // result + var c; + // check storage format + switch (y.storage()) { + case 'sparse': + c = algorithm10(y, x, addScalar, true); + break; + default: + c = algorithm14(y, x, addScalar, true); + break; + } + return c; + }, + + 'Array, any': function (x, y) { + // use matrix implementation + return algorithm14(matrix(x), y, addScalar, false).valueOf(); }, - 'BigNumber, BigNumber': function (x, y) { - return x.plus(y); - }, - - 'Complex, Complex': function (x, y) { - return new type.Complex( - x.re + y.re, - x.im + y.im - ); - }, - - 'Unit, Unit': function (x, y) { - if (x.value == null) throw new Error('Parameter x contains a unit with undefined value'); - if (y.value == null) throw new Error('Parameter y contains a unit with undefined value'); - if (!x.equalBase(y)) throw new Error('Units do not match'); - - var res = x.clone(); - res.value += y.value; - res.fixPrefix = false; - return res; - }, - - 'Array | Matrix, any': function (x, y) { - return collection.deepMap2(x, y, add); - }, - - 'any, Array | Matrix': function (x, y) { - return collection.deepMap2(x, y, add); - }, - - 'string, string': function (x, y) { - return x + y; + 'any, Array': function (x, y) { + // use matrix implementation + return algorithm14(matrix(y), x, addScalar, true).valueOf(); } }); - + return add; } diff --git a/lib/function/arithmetic/addScalar.js b/lib/function/arithmetic/addScalar.js new file mode 100644 index 000000000..57233bfb7 --- /dev/null +++ b/lib/function/arithmetic/addScalar.js @@ -0,0 +1,55 @@ +'use strict'; + +function factory(type, config, load, typed) { + + /** + * Add two scalar values, `x + y`. + * This function is meant for internal use: it is used by the public function + * `add` + * + * This function does not support collections (Array or Matrix), and does + * not validate the number of of inputs. + * + * @param {Number | BigNumber | Boolean | Complex | Unit | null} x First value to add + * @param {Number | BigNumber | Boolean | Complex | null} y Second value to add + * @return {Number | BigNumber | Complex | Unit} Sum of `x` and `y` + * @private + */ + var addScalar = typed('addScalar', { + + 'number, number': function (x, y) { + return x + y; + }, + + 'Complex, Complex': function (x, y) { + return new type.Complex( + x.re + y.re, + x.im + y.im + ); + }, + + 'BigNumber, BigNumber': function (x, y) { + return x.plus(y); + }, + + 'Unit, Unit': function (x, y) { + if (x.value == null) throw new Error('Parameter x contains a unit with undefined value'); + if (y.value == null) throw new Error('Parameter y contains a unit with undefined value'); + if (!x.equalBase(y)) throw new Error('Units do not match'); + + var res = x.clone(); + res.value += y.value; + res.fixPrefix = false; + return res; + }, + + 'string, string': function (x, y) { + return x + y; + } + }); + + return addScalar; +} + +exports.name = 'addScalar'; +exports.factory = factory; diff --git a/lib/function/arithmetic/cube.js b/lib/function/arithmetic/cube.js index 2ecb84ed0..9893a5215 100644 --- a/lib/function/arithmetic/cube.js +++ b/lib/function/arithmetic/cube.js @@ -1,8 +1,9 @@ 'use strict'; function factory (type, config, load, typed) { + var collection = load(require('../../type/collection')); - var complexMultiply = load(require('./multiply')).signatures['Complex,Complex']; + var complexMultiply = load(require('./multiplyScalar')).signatures['Complex,Complex']; /** * Compute the cube of a value, `x * x * x`. diff --git a/lib/function/arithmetic/divide.js b/lib/function/arithmetic/divide.js index 6ce967276..3b36af1ce 100644 --- a/lib/function/arithmetic/divide.js +++ b/lib/function/arithmetic/divide.js @@ -1,11 +1,15 @@ 'use strict'; function factory (type, config, load, typed) { - var collection = load(require('../../type/collection')); + var divideScalar = load(require('./divideScalar')); var multiply = load(require('./multiply')); var inv = load(require('../matrix/inv')); + var matrix = load(require('../construction/matrix')); + var algorithm11 = load(require('../../type/matrix/util/algorithm11')); + var algorithm14 = load(require('../../type/matrix/util/algorithm14')); + /** * Divide two values, `x / y`. * To divide matrices, `x` is multiplied with the inverse of `y`: `x * inv(y)`. @@ -38,6 +42,7 @@ function factory (type, config, load, typed) { * @return {Number | BigNumber | Complex | Unit | Array | Matrix} Quotient, `x / y` */ return typed('divide', { + 'any, any': divideScalar, 'Array | Matrix, Array | Matrix': function (x, y) { @@ -48,8 +53,25 @@ function factory (type, config, load, typed) { return multiply(x, inv(y)); }, - 'Array | Matrix, any': function (x, y) { - return collection.deepMap2(x, y, divideScalar); + 'Matrix, any': function (x, y) { + // result + var c; + + // process storage format + switch (x.storage()) { + case 'sparse': + c = algorithm11(x, y, divideScalar, false); + break; + case 'dense': + c = algorithm14(x, y, divideScalar, false); + break; + } + return c; + }, + + 'Array, any': function (x, y) { + // use matrix implementation + return algorithm14(matrix(x), y, divideScalar, false).valueOf(); }, 'any, Array | Matrix': function (x, y) { diff --git a/lib/function/arithmetic/dotDivide.js b/lib/function/arithmetic/dotDivide.js index 1d0cdd946..7d5014d38 100644 --- a/lib/function/arithmetic/dotDivide.js +++ b/lib/function/arithmetic/dotDivide.js @@ -1,8 +1,17 @@ 'use strict'; function factory (type, config, load, typed) { - var collection = load(require('../../type/collection')); + + var matrix = load(require('../construction/matrix')); var divideScalar = load(require('./divideScalar')); + + var algorithm02 = load(require('../../type/matrix/util/algorithm02')); + var algorithm03 = load(require('../../type/matrix/util/algorithm03')); + var algorithm07 = load(require('../../type/matrix/util/algorithm07')); + var algorithm11 = load(require('../../type/matrix/util/algorithm11')); + var algorithm12 = load(require('../../type/matrix/util/algorithm12')); + var algorithm13 = load(require('../../type/matrix/util/algorithm13')); + var algorithm14 = load(require('../../type/matrix/util/algorithm14')); /** * Divide two matrices element wise. The function accepts both matrices and @@ -30,11 +39,101 @@ function factory (type, config, load, typed) { * @param {Number | BigNumber | Boolean | Complex | Unit | Array | Matrix | null} y Denominator * @return {Number | BigNumber | Complex | Unit | Array | Matrix} Quotient, `x ./ y` */ - return typed('dotDivide', { - 'any, any': function (x, y) { - return collection.deepMap2(x, y, divideScalar); + var dotDivide = typed('dotDivide', { + + 'any, any': divideScalar, + + 'Matrix, Matrix': function (x, y) { + // result + var c; + + // process matrix storage + switch (x.storage()) { + case 'sparse': + switch (y.storage()) { + case 'sparse': + // sparse ./ sparse + c = algorithm07(x, y, divideScalar, false); + break; + default: + // sparse ./ dense + c = algorithm02(y, x, divideScalar, true); + break; + } + break; + default: + switch (y.storage()) { + case 'sparse': + // dense ./ sparse + c = algorithm03(x, y, divideScalar, false); + break; + default: + // dense ./ dense + c = algorithm13(x, y, divideScalar); + break; + } + break; + } + return c; + }, + + 'Array, Array': function (x, y) { + // use matrix implementation + return dotDivide(matrix(x), matrix(y)).valueOf(); + }, + + 'Array, Matrix': function (x, y) { + // use matrix implementation + return dotDivide(matrix(x), y); + }, + + 'Matrix, Array': function (x, y) { + // use matrix implementation + return dotDivide(x, matrix(y)); + }, + + 'Matrix, any': function (x, y) { + // result + var c; + // check storage format + switch (x.storage()) { + case 'sparse': + c = algorithm11(x, y, divideScalar, false); + break; + default: + c = algorithm14(x, y, divideScalar, false); + break; + } + return c; + }, + + 'any, Matrix': function (x, y) { + // result + var c; + // check storage format + switch (y.storage()) { + case 'sparse': + c = algorithm12(y, x, divideScalar, true); + break; + default: + c = algorithm14(y, x, divideScalar, true); + break; + } + return c; + }, + + 'Array, any': function (x, y) { + // use matrix implementation + return algorithm14(matrix(x), y, divideScalar, false).valueOf(); + }, + + 'any, Array': function (x, y) { + // use matrix implementation + return algorithm14(matrix(y), x, divideScalar, true).valueOf(); } }); + + return dotDivide; } exports.name = 'dotDivide'; diff --git a/lib/function/arithmetic/dotMultiply.js b/lib/function/arithmetic/dotMultiply.js index d45c6cb36..b5eca7879 100644 --- a/lib/function/arithmetic/dotMultiply.js +++ b/lib/function/arithmetic/dotMultiply.js @@ -1,10 +1,15 @@ 'use strict'; -var size = require('../../util/array').size; - function factory (type, config, load, typed) { - var collection = load(require('../../type/collection')); - var multiply = load(require('./multiply')); + + var matrix = load(require('../construction/matrix')); + var multiplyScalar = load(require('./multiplyScalar')); + + var algorithm02 = load(require('../../type/matrix/util/algorithm02')); + var algorithm09 = load(require('../../type/matrix/util/algorithm09')); + var algorithm11 = load(require('../../type/matrix/util/algorithm11')); + var algorithm13 = load(require('../../type/matrix/util/algorithm13')); + var algorithm14 = load(require('../../type/matrix/util/algorithm14')); /** * Multiply two matrices element wise. The function accepts both matrices and @@ -32,11 +37,101 @@ function factory (type, config, load, typed) { * @param {Number | BigNumber | Boolean | Complex | Unit | Array | Matrix | null} y Right hand value * @return {Number | BigNumber | Complex | Unit | Array | Matrix} Multiplication of `x` and `y` */ - return typed('dotMultiply', { - 'any, any': function (x, y) { - return collection.deepMap2(x, y, multiply); + var dotMultiply = typed('dotMultiply', { + + 'any, any': multiplyScalar, + + 'Matrix, Matrix': function (x, y) { + // result + var c; + + // process matrix storage + switch (x.storage()) { + case 'sparse': + switch (y.storage()) { + case 'sparse': + // sparse .* sparse + c = algorithm09(x, y, multiplyScalar, false); + break; + default: + // sparse .* dense + c = algorithm02(y, x, multiplyScalar, true); + break; + } + break; + default: + switch (y.storage()) { + case 'sparse': + // dense .* sparse + c = algorithm02(x, y, multiplyScalar, false); + break; + default: + // dense .* dense + c = algorithm13(x, y, multiplyScalar); + break; + } + break; + } + return c; + }, + + 'Array, Array': function (x, y) { + // use matrix implementation + return dotMultiply(matrix(x), matrix(y)).valueOf(); + }, + + 'Array, Matrix': function (x, y) { + // use matrix implementation + return dotMultiply(matrix(x), y); + }, + + 'Matrix, Array': function (x, y) { + // use matrix implementation + return dotMultiply(x, matrix(y)); + }, + + 'Matrix, any': function (x, y) { + // result + var c; + // check storage format + switch (x.storage()) { + case 'sparse': + c = algorithm11(x, y, multiplyScalar, false); + break; + default: + c = algorithm14(x, y, multiplyScalar, false); + break; + } + return c; + }, + + 'any, Matrix': function (x, y) { + // result + var c; + // check storage format + switch (y.storage()) { + case 'sparse': + c = algorithm11(y, x, multiplyScalar, true); + break; + default: + c = algorithm14(y, x, multiplyScalar, true); + break; + } + return c; + }, + + 'Array, any': function (x, y) { + // use matrix implementation + return algorithm14(matrix(x), y, multiplyScalar, false).valueOf(); + }, + + 'any, Array': function (x, y) { + // use matrix implementation + return algorithm14(matrix(y), x, multiplyScalar, true).valueOf(); } }); + + return dotMultiply; } exports.name = 'dotMultiply'; diff --git a/lib/function/arithmetic/dotPow.js b/lib/function/arithmetic/dotPow.js index dfd58b7b8..1e12309fa 100644 --- a/lib/function/arithmetic/dotPow.js +++ b/lib/function/arithmetic/dotPow.js @@ -1,9 +1,17 @@ 'use strict'; function factory (type, config, load, typed) { - var collection = load(require('../../type/collection')); + + var matrix = load(require('../construction/matrix')); var pow = load(require('./pow')); + var algorithm03 = load(require('../../type/matrix/util/algorithm03')); + var algorithm07 = load(require('../../type/matrix/util/algorithm07')); + var algorithm11 = load(require('../../type/matrix/util/algorithm11')); + var algorithm12 = load(require('../../type/matrix/util/algorithm12')); + var algorithm13 = load(require('../../type/matrix/util/algorithm13')); + var algorithm14 = load(require('../../type/matrix/util/algorithm14')); + /** * Calculates the power of x to y element wise. * @@ -27,11 +35,101 @@ function factory (type, config, load, typed) { * @param {Number | BigNumber | Boolean | Complex | Unit | Array | Matrix | null} y The exponent * @return {Number | BigNumber | Complex | Unit | Array | Matrix} The value of `x` to the power `y` */ - return typed('dotMultiply', { - 'any, any': function (x, y) { - return collection.deepMap2(x, y, pow); + var dotPow = typed('dotPow', { + + 'any, any': pow, + + 'Matrix, Matrix': function (x, y) { + // result + var c; + + // process matrix storage + switch (x.storage()) { + case 'sparse': + switch (y.storage()) { + case 'sparse': + // sparse .^ sparse + c = algorithm07(x, y, pow, false); + break; + default: + // sparse .^ dense + c = algorithm03(y, x, pow, true); + break; + } + break; + default: + switch (y.storage()) { + case 'sparse': + // dense .^ sparse + c = algorithm03(x, y, pow, false); + break; + default: + // dense .^ dense + c = algorithm13(x, y, pow); + break; + } + break; + } + return c; + }, + + 'Array, Array': function (x, y) { + // use matrix implementation + return dotPow(matrix(x), matrix(y)).valueOf(); + }, + + 'Array, Matrix': function (x, y) { + // use matrix implementation + return dotPow(matrix(x), y); + }, + + 'Matrix, Array': function (x, y) { + // use matrix implementation + return dotPow(x, matrix(y)); + }, + + 'Matrix, any': function (x, y) { + // result + var c; + // check storage format + switch (x.storage()) { + case 'sparse': + c = algorithm11(x, y, dotPow, false); + break; + default: + c = algorithm14(x, y, dotPow, false); + break; + } + return c; + }, + + 'any, Matrix': function (x, y) { + // result + var c; + // check storage format + switch (y.storage()) { + case 'sparse': + c = algorithm12(y, x, dotPow, true); + break; + default: + c = algorithm14(y, x, dotPow, true); + break; + } + return c; + }, + + 'Array, any': function (x, y) { + // use matrix implementation + return algorithm14(matrix(x), y, dotPow, false).valueOf(); + }, + + 'any, Array': function (x, y) { + // use matrix implementation + return algorithm14(matrix(y), x, dotPow, true).valueOf(); } }); + + return dotPow; } exports.name = 'dotPow'; diff --git a/lib/function/arithmetic/exp.js b/lib/function/arithmetic/exp.js index 60a93823c..041e9085e 100644 --- a/lib/function/arithmetic/exp.js +++ b/lib/function/arithmetic/exp.js @@ -47,6 +47,7 @@ function factory (type, config, load, typed) { }, 'Array | Matrix': function (x) { + // TODO: exp(sparse) should return a dense matrix since exp(0)==1 return collection.deepMap(x, exp); } }); diff --git a/lib/function/arithmetic/gcd.js b/lib/function/arithmetic/gcd.js index 052e1246f..e92934df7 100644 --- a/lib/function/arithmetic/gcd.js +++ b/lib/function/arithmetic/gcd.js @@ -3,7 +3,14 @@ var isInteger = require('../../util/number').isInteger; function factory (type, config, load, typed) { - var collection = load(require('../../type/collection')); + + var matrix = load(require('../construction/matrix')); + + var algorithm01 = load(require('../../type/matrix/util/algorithm01')); + var algorithm04 = load(require('../../type/matrix/util/algorithm04')); + var algorithm10 = load(require('../../type/matrix/util/algorithm10')); + var algorithm13 = load(require('../../type/matrix/util/algorithm13')); + var algorithm14 = load(require('../../type/matrix/util/algorithm14')); /** * Calculate the greatest common divisor for two or more values or arrays. @@ -31,16 +38,98 @@ function factory (type, config, load, typed) { * @return {Number | BigNumber | Array | Matrix} The greatest common divisor */ var gcd = typed('gcd', { + 'number, number': _gcd, 'BigNumber, BigNumber': _gcdBigNumber, - 'Array | Matrix, Array | Matrix | number | BigNumber': function (a, b) { - return collection.deepMap2(a, b, gcd); + 'Matrix, Matrix': function (x, y) { + // result + var c; + + // process matrix storage + switch (x.storage()) { + case 'sparse': + switch (y.storage()) { + case 'sparse': + // sparse + sparse + c = algorithm04(x, y, gcd); + break; + default: + // sparse + dense + c = algorithm01(y, x, gcd, true); + break; + } + break; + default: + switch (y.storage()) { + case 'sparse': + // dense + sparse + c = algorithm01(x, y, gcd, false); + break; + default: + // dense + dense + c = algorithm13(x, y, gcd); + break; + } + break; + } + return c; }, - 'number | BigNumber, Array | Matrix': function (a, b) { - return collection.deepMap2(a, b, gcd); + 'Array, Array': function (x, y) { + // use matrix implementation + return gcd(matrix(x), matrix(y)).valueOf(); + }, + + 'Array, Matrix': function (x, y) { + // use matrix implementation + return gcd(matrix(x), y); + }, + + 'Matrix, Array': function (x, y) { + // use matrix implementation + return gcd(x, matrix(y)); + }, + + 'Matrix, number | BigNumber': function (x, y) { + // result + var c; + // check storage format + switch (x.storage()) { + case 'sparse': + c = algorithm10(x, y, gcd, false); + break; + default: + c = algorithm14(x, y, gcd, false); + break; + } + return c; + }, + + 'number | BigNumber, Matrix': function (x, y) { + // result + var c; + // check storage format + switch (y.storage()) { + case 'sparse': + c = algorithm10(y, x, gcd, true); + break; + default: + c = algorithm14(y, x, gcd, true); + break; + } + return c; + }, + + 'Array, number | BigNumber': function (x, y) { + // use matrix implementation + return algorithm14(matrix(x), y, gcd, false).valueOf(); + }, + + 'number | BigNumber, Array': function (x, y) { + // use matrix implementation + return algorithm14(matrix(y), x, gcd, true).valueOf(); }, // TODO: need a smarter notation here diff --git a/lib/function/arithmetic/lcm.js b/lib/function/arithmetic/lcm.js index 13346494b..825df566b 100644 --- a/lib/function/arithmetic/lcm.js +++ b/lib/function/arithmetic/lcm.js @@ -3,7 +3,14 @@ var isInteger = require('../../util/number').isInteger; function factory (type, config, load, typed) { - var collection = load(require('../../type/collection')); + + var matrix = load(require('../construction/matrix')); + + var algorithm02 = load(require('../../type/matrix/util/algorithm02')); + var algorithm06 = load(require('../../type/matrix/util/algorithm06')); + var algorithm11 = load(require('../../type/matrix/util/algorithm11')); + var algorithm13 = load(require('../../type/matrix/util/algorithm13')); + var algorithm14 = load(require('../../type/matrix/util/algorithm14')); /** * Calculate the least common multiple for two or more values or arrays. @@ -39,12 +46,93 @@ function factory (type, config, load, typed) { 'BigNumber, BigNumber': _lcmBigNumber, - 'Array | Matrix, Array | Matrix | number | BigNumber': function (a, b) { - return collection.deepMap2(a, b, lcm); + 'Matrix, Matrix': function (x, y) { + // result + var c; + + // process matrix storage + switch (x.storage()) { + case 'sparse': + switch (y.storage()) { + case 'sparse': + // sparse + sparse + c = algorithm06(x, y, lcm); + break; + default: + // sparse + dense + c = algorithm02(y, x, lcm, true); + break; + } + break; + default: + switch (y.storage()) { + case 'sparse': + // dense + sparse + c = algorithm02(x, y, lcm, false); + break; + default: + // dense + dense + c = algorithm13(x, y, lcm); + break; + } + break; + } + return c; }, - 'number | BigNumber, Array | Matrix': function (a, b) { - return collection.deepMap2(a, b, lcm); + 'Array, Array': function (x, y) { + // use matrix implementation + return lcm(matrix(x), matrix(y)).valueOf(); + }, + + 'Array, Matrix': function (x, y) { + // use matrix implementation + return lcm(matrix(x), y); + }, + + 'Matrix, Array': function (x, y) { + // use matrix implementation + return lcm(x, matrix(y)); + }, + + 'Matrix, number | BigNumber': function (x, y) { + // result + var c; + // check storage format + switch (x.storage()) { + case 'sparse': + c = algorithm11(x, y, lcm, false); + break; + default: + c = algorithm14(x, y, lcm, false); + break; + } + return c; + }, + + 'number | BigNumber, Matrix': function (x, y) { + // result + var c; + // check storage format + switch (y.storage()) { + case 'sparse': + c = algorithm11(y, x, lcm, true); + break; + default: + c = algorithm14(y, x, lcm, true); + break; + } + return c; + }, + + 'Array, number | BigNumber': function (x, y) { + // use matrix implementation + return algorithm14(matrix(x), y, lcm, false).valueOf(); + }, + + 'number | BigNumber, Array': function (x, y) { + // use matrix implementation + return algorithm14(matrix(y), x, lcm, true).valueOf(); }, // TODO: need a smarter notation here diff --git a/lib/function/arithmetic/mod.js b/lib/function/arithmetic/mod.js index 02339b6d6..ffdee965e 100644 --- a/lib/function/arithmetic/mod.js +++ b/lib/function/arithmetic/mod.js @@ -1,8 +1,17 @@ 'use strict'; function factory (type, config, load, typed) { - var collection = load(require('../../type/collection')); + var matrix = load(require('../construction/matrix')); + + var algorithm02 = load(require('../../type/matrix/util/algorithm02')); + var algorithm03 = load(require('../../type/matrix/util/algorithm03')); + var algorithm05 = load(require('../../type/matrix/util/algorithm05')); + var algorithm11 = load(require('../../type/matrix/util/algorithm11')); + var algorithm12 = load(require('../../type/matrix/util/algorithm12')); + var algorithm13 = load(require('../../type/matrix/util/algorithm13')); + var algorithm14 = load(require('../../type/matrix/util/algorithm14')); + /** * Calculates the modulus, the remainder of an integer division. * @@ -39,18 +48,100 @@ function factory (type, config, load, typed) { * @return {Number | BigNumber | Array | Matrix} Returns the remainder of `x` divided by `y`. */ var mod = typed('mod', { + 'number, number': _mod, 'BigNumber, BigNumber': function (x, y) { return y.isZero() ? x : x.mod(y); }, + + 'Matrix, Matrix': function (x, y) { + // result + var c; - 'Array | Matrix, any': function (x, y) { - return collection.deepMap2(x, y, mod); + // process matrix storage + switch (x.storage()) { + case 'sparse': + switch (y.storage()) { + case 'sparse': + // mod(sparse, sparse) + c = algorithm05(x, y, mod, false); + break; + default: + // mod(sparse, dense) + c = algorithm02(y, x, mod, true); + break; + } + break; + default: + switch (y.storage()) { + case 'sparse': + // mod(dense, sparse) + c = algorithm03(x, y, mod, false); + break; + default: + // mod(dense, dense) + c = algorithm13(x, y, mod); + break; + } + break; + } + return c; + }, + + 'Array, Array': function (x, y) { + // use matrix implementation + return mod(matrix(x), matrix(y)).valueOf(); }, - 'any, Array | Matrix': function (x, y) { - return collection.deepMap2(x, y, mod); + 'Array, Matrix': function (x, y) { + // use matrix implementation + return mod(matrix(x), y); + }, + + 'Matrix, Array': function (x, y) { + // use matrix implementation + return mod(x, matrix(y)); + }, + + 'Matrix, any': function (x, y) { + // result + var c; + // check storage format + switch (x.storage()) { + case 'sparse': + c = algorithm11(x, y, mod, false); + break; + default: + c = algorithm14(x, y, mod, false); + break; + } + return c; + }, + + 'any, Matrix': function (x, y) { + // result + var c; + // check storage format + switch (y.storage()) { + case 'sparse': + c = algorithm12(y, x, mod, true); + break; + default: + c = algorithm14(y, x, mod, true); + break; + } + return c; + }, + + 'Array, any': function (x, y) { + // use matrix implementation + return algorithm14(matrix(x), y, mod, false).valueOf(); + }, + + 'any, Array': function (x, y) { + // use matrix implementation + return algorithm14(matrix(y), x, mod, true).valueOf(); } }); diff --git a/lib/function/arithmetic/multiply.js b/lib/function/arithmetic/multiply.js index 90955b3d8..dea65cb39 100644 --- a/lib/function/arithmetic/multiply.js +++ b/lib/function/arithmetic/multiply.js @@ -7,14 +7,15 @@ var array = util.array; function factory (type, config, load, typed) { var matrix = load(require('../construction/matrix')); - var add = load(require('./add')); - var equal = load(require('../relational/equal')); - - var collection = load(require('../../type/collection')); + var addScalar = load(require('./addScalar')); + var multiplyScalar = load(require('./multiplyScalar')); + var equalScalar = load(require('../relational/equalScalar')); + var algorithm11 = load(require('../../type/matrix/util/algorithm11')); + var algorithm14 = load(require('../../type/matrix/util/algorithm14')); + var DenseMatrix = type.DenseMatrix; var SparseMatrix = type.SparseMatrix; - var Spa = type.Spa; /** * Multiply two values, `x * y`. The result is squeezed. @@ -49,32 +50,7 @@ function factory (type, config, load, typed) { */ var multiply = typed('multiply', { - 'number, number': function (x, y) { - return x * y; - }, - - 'BigNumber, BigNumber': function (x, y) { - return x.times(y); - }, - - 'Complex, Complex': function (x, y) { - return new type.Complex( - x.re * y.re - x.im * y.im, - x.re * y.im + x.im * y.re - ); - }, - - 'number, Unit': function (x, y) { - var res = y.clone(); - res.value = (res.value === null) ? res._normalize(x) : (res.value * x); - return res; - }, - - 'Unit, number': function (x, y) { - var res = x.clone(); - res.value = (res.value === null) ? res._normalize(y) : (res.value * y); - return res; - }, + 'any, any': multiplyScalar, 'Array, Array': function (x, y) { // check dimensions @@ -123,22 +99,45 @@ function factory (type, config, load, typed) { return multiply(matrix(x, y.storage()), y); }, - 'Array, any': function (x, y) { - return collection.deepMap2(x, y, multiply); - }, - 'Matrix, any': function (x, y) { - // use matrix map, skip zeros since 0 * X = 0 - return x.map(function (v) { - return multiply(v, y); - }, true); + // result + var c; + + // process storage format + switch (x.storage()) { + case 'sparse': + c = algorithm11(x, y, multiplyScalar, false); + break; + case 'dense': + c = algorithm14(x, y, multiplyScalar, false); + break; + } + return c; }, - 'any, Array | Matrix': function (x, y) { - // use matrix map, skip zeros since 0 * X = 0 - return y.map(function (v) { - return multiply(v, x); - }, true); + 'any, Matrix': function (x, y) { + // result + var c; + // check storage format + switch (y.storage()) { + case 'sparse': + c = algorithm11(y, x, multiplyScalar, true); + break; + case 'dense': + c = algorithm14(y, x, multiplyScalar, true); + break; + } + return c; + }, + + 'Array, any': function (x, y) { + // use matrix implementation + return algorithm14(matrix(x), y, multiplyScalar, false).valueOf(); + }, + + 'any, Array': function (x, y) { + // use matrix implementation + return algorithm14(matrix(y), x, multiplyScalar, true).valueOf(); } }); @@ -207,15 +206,23 @@ function factory (type, config, load, typed) { // a dense var adata = a._data; + var adt = a._datatype; // b dense var bdata = b._data; + var bdt = b._datatype; - // result - var c = 0; + // process data types + var dt = adt && bdt && adt === bdt ? adt : undefined; + // multiply & add scalar implementations + var mf = dt ? multiplyScalar.signatures[dt + ',' + dt] || multiplyScalar : multiplyScalar; + var af = dt ? addScalar.signatures[dt + ',' + dt] || addScalar : addScalar; + + // result (do not initialize it with zero) + var c = mf(adata[0], bdata[0]); // loop data - for (var i = 0; i < n; i++) { + for (var i = 1; i < n; i++) { // multiply and accumulate - c = add(c, multiply(adata[i], bdata[i])); + c = af(c, mf(adata[i], bdata[i])); } return c; }; @@ -249,24 +256,32 @@ function factory (type, config, load, typed) { // a dense var adata = a._data; var asize = a._size; + var adt = a._datatype; // b dense var bdata = b._data; var bsize = b._size; + var bdt = b._datatype; // rows & columns var alength = asize[0]; var bcolumns = bsize[1]; + // process data types + var dt = adt && bdt && adt === bdt ? adt : undefined; + // multiply & add scalar implementations + var mf = dt ? multiplyScalar.signatures[dt + ',' + dt] || multiplyScalar : multiplyScalar; + var af = dt ? addScalar.signatures[dt + ',' + dt] || addScalar : addScalar; + // result - var c = new Array(bcolumns); + var c = []; // loop matrix columns for (var j = 0; j < bcolumns; j++) { - // sum - var sum = 0; + // sum (do not initialize it with zero) + var sum = mf(adata[0], bdata[0][j]); // loop vector - for (var i = 0; i < alength; i++) { + for (var i = 1; i < alength; i++) { // multiply & accumulate - sum = add(sum, multiply(adata[i], bdata[i][j])); + sum = af(sum, mf(adata[i], bdata[i][j])); } c[j] = sum; } @@ -278,7 +293,8 @@ function factory (type, config, load, typed) { // return matrix return new DenseMatrix({ data: c, - size: [bcolumns] + size: [bcolumns], + datatype: dt }); }; @@ -344,25 +360,33 @@ function factory (type, config, load, typed) { // a dense var adata = a._data; var asize = a._size; + var adt = a._datatype; // b dense var bdata = b._data; + var bdt = b._datatype; // rows & columns var arows = asize[0]; var acolumns = asize[1]; + // process data types + var dt = adt && bdt && adt === bdt ? adt : undefined; + // multiply & add scalar implementations + var mf = dt ? multiplyScalar.signatures[dt + ',' + dt] || multiplyScalar : multiplyScalar; + var af = dt ? addScalar.signatures[dt + ',' + dt] || addScalar : addScalar; + // result - var c = new Array(arows); + var c = []; // loop matrix a rows for (var i = 0; i < arows; i++) { // current row var row = adata[i]; - // sum - var sum = 0; + // sum (do not initialize it with zero) + var sum = mf(row[0], bdata[0]); // loop matrix a columns - for (var j = 0; j < acolumns; j++) { + for (var j = 1; j < acolumns; j++) { // multiply & accumulate - sum = add(sum, multiply(row[j], bdata[j])); + sum = af(sum, mf(row[j], bdata[j])); } c[i] = sum; } @@ -373,7 +397,8 @@ function factory (type, config, load, typed) { // return matrix return new DenseMatrix({ data: c, - size: [arows] + size: [arows], + datatype: dt }); }; @@ -389,31 +414,39 @@ function factory (type, config, load, typed) { // a dense var adata = a._data; var asize = a._size; + var adt = a._datatype; // b dense var bdata = b._data; var bsize = b._size; + var bdt = b._datatype; // rows & columns var arows = asize[0]; var acolumns = asize[1]; var bcolumns = bsize[1]; + // process data types + var dt = adt && bdt && adt === bdt ? adt : undefined; + // multiply & add scalar implementations + var mf = dt ? multiplyScalar.signatures[dt + ',' + dt] || multiplyScalar : multiplyScalar; + var af = dt ? addScalar.signatures[dt + ',' + dt] || addScalar : addScalar; + // result - var c = new Array(arows); + var c = []; // loop matrix a rows for (var i = 0; i < arows; i++) { // current row var row = adata[i]; // initialize row array - c[i] = new Array(bcolumns); + c[i] = []; // loop matrix b columns for (var j = 0; j < bcolumns; j++) { - // sum - var sum = 0; + // sum (avoid initializing sum to zero) + var sum = mf(row[0], bdata[0][j]); // loop matrix a columns - for (var x = 0; x < acolumns; x++) { + for (var x = 1; x < acolumns; x++) { // multiply & accumulate - sum = add(sum, multiply(row[x], bdata[x][j])); + sum = af(sum, mf(row[x], bdata[x][j])); } c[i][j] = sum; } @@ -425,7 +458,8 @@ function factory (type, config, load, typed) { // return matrix return new DenseMatrix({ data: c, - size: [arows, bcolumns] + size: [arows, bcolumns], + datatype: dt }); }; @@ -433,56 +467,97 @@ function factory (type, config, load, typed) { * C = A * B * * @param {Matrix} a DenseMatrix (MxN) - * @param {Matrix} b SparseMatrix (NxC) + * @param {Matrix} b SparseMatrix (NxC) * - * @return {Matrix} DenseMatrix (MxC) + * @return {Matrix} SparseMatrix (MxC) */ var _multiplyDenseMatrixSparseMatrix = function (a, b) { // a dense var adata = a._data; var asize = a._size; + var adt = a._datatype; // b sparse var bvalues = b._values; var bindex = b._index; var bptr = b._ptr; var bsize = b._size; + var bdt = b._datatype; + // validate b matrix + if (!bvalues) + throw new Error('Cannot multiply Dense Matrix times Pattern only Matrix'); // rows & columns var arows = asize[0]; var bcolumns = bsize[1]; - // result - var c = new Array(arows); + var cvalues = []; + var cindex = []; + var cptr = []; + // c matrix + var c = new SparseMatrix({ + values : cvalues, + index: cindex, + ptr: cptr, + size: [arows, bcolumns], + datatype: dt + }); + + // process data types + var dt = adt && bdt && adt === bdt ? adt : undefined; + // multiply & add scalar implementations + var mf = dt ? multiplyScalar.signatures[dt + ',' + dt] || multiplyScalar : multiplyScalar; + var af = dt ? addScalar.signatures[dt + ',' + dt] || addScalar : addScalar; - // loop a rows - for (var i = 0; i < arows; i++) { - // initialize row - c[i] = new Array(bcolumns); - // current row - var row = adata[i]; - // loop b columns - for (var j = 0; j < bcolumns; j++) { - // sum - var sum = 0; - // values & index in column j - for (var k0 = bptr[j], k1 = bptr[j + 1], k = k0; k < k1; k++) { - // row - var x = bindex[k]; - // multiply & accumulate - sum = add(sum, multiply(row[x], bvalues[k])); + // loop b columns + for (var jb = 0; jb < bcolumns; jb++) { + // update ptr + cptr[jb] = cindex.length; + // indeces in column jb + var kb0 = bptr[jb]; + var kb1 = bptr[jb + 1]; + // do not process column jb if no data exists + if (kb1 > kb0) { + // last row mark processed + var last = 0; + // loop a rows + for (var i = 0; i < arows; i++) { + // column mark + var mark = i + 1; + // C[i, jb] + var cij; + // values in b column j + for (var kb = kb0; kb < kb1; kb++) { + // row + var ib = bindex[kb]; + // check value has been initialized + if (last !== mark) { + // first value in column jb + cij = mf(adata[i][ib], bvalues[kb]); + // update mark + last = mark; + } + else { + // accumulate value + cij = af(cij, mf(adata[i][ib], bvalues[kb])); + } + } + // check column has been processed and value != 0 + if (last === mark && !equalScalar(cij, 0)) { + // push row & value + cindex.push(i); + cvalues.push(cij); + } } - c[i][j] = sum; } } + // update ptr + cptr[bcolumns] = cindex.length; // check we need to squeeze the result into a scalar if (arows === 1 && bcolumns === 1) - return c[0][0]; + return cvalues.length === 1 ? cvalues[0] : 0; - // return matrix - return new DenseMatrix({ - data: c, - size: [arows, bcolumns] - }); + // return sparse matrix + return c; }; /** @@ -498,8 +573,13 @@ function factory (type, config, load, typed) { var avalues = a._values; var aindex = a._index; var aptr = a._ptr; + var adt = a._datatype; + // validate a matrix + if (!avalues) + throw new Error('Cannot multiply Pattern only Matrix times Dense Matrix'); // b dense var bdata = b._data; + var bdt = b._datatype; // rows & columns var arows = a._size[0]; var brows = b._size[0]; @@ -507,34 +587,55 @@ function factory (type, config, load, typed) { var cvalues = []; var cindex = []; var cptr = []; + + // process data types + var dt = adt && bdt && adt === bdt ? adt : undefined; + // multiply & add scalar implementations + var mf = dt ? multiplyScalar.signatures[dt + ',' + dt] || multiplyScalar : multiplyScalar; + var af = dt ? addScalar.signatures[dt + ',' + dt] || addScalar : addScalar; - // create sparse accumulator - var spa = new Spa(arows); + // workspace + var x = []; + // vector with marks indicating a value x[i] exists in a given column + var w = []; // update ptr - cptr.push(0); + cptr[0] = 0; // rows in b for (var ib = 0; ib < brows; ib++) { // b[ib] var vbi = bdata[ib]; // check b[ib] != 0, avoid loops - if (!equal(vbi, 0)) { + if (!equalScalar(vbi, 0)) { // A values & index in ib column for (var ka0 = aptr[ib], ka1 = aptr[ib + 1], ka = ka0; ka < ka1; ka++) { // a row var ia = aindex[ka]; - // accumulate - spa.accumulate(ia, multiply(vbi, avalues[ka])); + // check value exists in current j + if (!w[ia]) { + // ia is new entry in j + w[ia] = true; + // add i to pattern of C + cindex.push(ia); + // x(ia) = A + x[ia] = mf(vbi, avalues[ka]); + } + else { + // i exists in C already + x[ia] = af(x[ia], mf(vbi, avalues[ka])); + } } } } - // process spa - spa.forEach(0, arows - 1, function (x, v) { - cindex.push(x); - cvalues.push(v); - }); + // copy values from x to column jb of c + for (var p1 = cindex.length, p = 0; p < p1; p++) { + // row + var ic = cindex[p]; + // copy value + cvalues[p] = x[ic]; + } // update ptr - cptr.push(cvalues.length); + cptr[1] = cindex.length; // check we need to squeeze the result into a scalar if (arows === 1) @@ -545,7 +646,8 @@ function factory (type, config, load, typed) { values : cvalues, index: cindex, ptr: cptr, - size: [arows, 1] + size: [arows, 1], + datatype: dt }); }; @@ -553,7 +655,7 @@ function factory (type, config, load, typed) { * C = A * B * * @param {Matrix} a SparseMatrix (MxN) - * @param {Matrix} b DenseMatrix (NxC) + * @param {Matrix} b DenseMatrix (NxC) * * @return {Matrix} SparseMatrix (MxC) */ @@ -562,61 +664,90 @@ function factory (type, config, load, typed) { var avalues = a._values; var aindex = a._index; var aptr = a._ptr; + var adt = a._datatype; + // validate a matrix + if (!avalues) + throw new Error('Cannot multiply Pattern only Matrix times Dense Matrix'); // b dense var bdata = b._data; + var bdt = b._datatype; // rows & columns var arows = a._size[0]; var brows = b._size[0]; var bcolumns = b._size[1]; + + // process data types + var dt = adt && bdt && adt === bdt ? adt : undefined; + // multiply & add scalar implementations + var mf = dt ? multiplyScalar.signatures[dt + ',' + dt] || multiplyScalar : multiplyScalar; + var af = dt ? addScalar.signatures[dt + ',' + dt] || addScalar : addScalar; + // result var cvalues = []; var cindex = []; var cptr = []; - - // process column - var processColumn = function (j, v) { - cindex.push(j); - cvalues.push(v); - }; + // c matrix + var c = new SparseMatrix({ + values : cvalues, + index: cindex, + ptr: cptr, + size: [arows, bcolumns], + datatype: dt + }); + // workspace + var x = []; + // vector with marks indicating a value x[i] exists in a given column + var w = []; // loop b columns for (var jb = 0; jb < bcolumns; jb++) { // update ptr - cptr.push(cvalues.length); - // create sparse accumulator - var spa = new Spa(arows); + cptr[jb] = cindex.length; + // mark in workspace for current column + var mark = jb + 1; // rows in jb for (var ib = 0; ib < brows; ib++) { // b[ib, jb] var vbij = bdata[ib][jb]; // check b[ib, jb] != 0, avoid loops - if (!equal(vbij, 0)) { + if (!equalScalar(vbij, 0)) { // A values & index in ib column for (var ka0 = aptr[ib], ka1 = aptr[ib + 1], ka = ka0; ka < ka1; ka++) { // a row var ia = aindex[ka]; - // accumulate - spa.accumulate(ia, multiply(vbij, avalues[ka])); + // check value exists in current j + if (w[ia] !== mark) { + // ia is new entry in j + w[ia] = mark; + // add i to pattern of C + cindex.push(ia); + // x(ia) = A + x[ia] = mf(vbij, avalues[ka]); + } + else { + // i exists in C already + x[ia] = af(x[ia], mf(vbij, avalues[ka])); + } } } } - // process sparse accumulator - spa.forEach(0, arows - 1, processColumn); + // copy values from x to column jb of c + for (var p0 = cptr[jb], p1 = cindex.length, p = p0; p < p1; p++) { + // row + var ic = cindex[p]; + // copy value + cvalues[p] = x[ic]; + } } // update ptr - cptr.push(cvalues.length); + cptr[bcolumns] = cindex.length; // check we need to squeeze the result into a scalar if (arows === 1 && bcolumns === 1) return cvalues.length === 1 ? cvalues[0] : 0; // return sparse matrix - return new SparseMatrix({ - values : cvalues, - index: cindex, - ptr: cptr, - size: [arows, bcolumns] - }); + return c; }; /** @@ -632,59 +763,106 @@ function factory (type, config, load, typed) { var avalues = a._values; var aindex = a._index; var aptr = a._ptr; + var adt = a._datatype; // b sparse var bvalues = b._values; var bindex = b._index; var bptr = b._ptr; + var bdt = b._datatype; + // process data types + var dt = adt && bdt && adt === bdt ? adt : undefined; + // multiply & add scalar implementations + var mf = dt ? multiplyScalar.signatures[dt + ',' + dt] || multiplyScalar : multiplyScalar; + var af = dt ? addScalar.signatures[dt + ',' + dt] || addScalar : addScalar; // rows & columns var arows = a._size[0]; var bcolumns = b._size[1]; + // flag indicating both matrices (a & b) contain data + var values = avalues && bvalues; // result - var cvalues = []; + var cvalues = values ? [] : undefined; var cindex = []; var cptr = []; - - // process column in C - var processColumn = function (i, v) { - cindex.push(i); - cvalues.push(v); - }; - - // loop b columns - for (var jb = 0; jb < bcolumns; jb++) { - // update ptr - cptr.push(cvalues.length); - // create sparse accumulator - var spa = new Spa(arows); - // B values & index in j - for (var kb0 = bptr[jb], kb1 = bptr[jb + 1], kb = kb0; kb < kb1; kb++) { - // b row - var ib = bindex[kb]; - // A values & index in ib column - for (var ka0 = aptr[ib], ka1 = aptr[ib + 1], ka = ka0; ka < ka1; ka++) { - // a row - var ia = aindex[ka]; - // accumulate - spa.accumulate(ia, multiply(bvalues[kb], avalues[ka])); - } - } - // process sparse accumulator - spa.forEach(0, arows - 1, processColumn); - } - // update ptr - cptr.push(cvalues.length); - - // check we need to squeeze the result into a scalar - if (arows === 1 && bcolumns === 1) - return cvalues.length === 1 ? cvalues[0] : 0; - - // return sparse matrix - return new SparseMatrix({ + // c matrix + var c = new SparseMatrix({ values : cvalues, index: cindex, ptr: cptr, - size: [arows, bcolumns] + size: [arows, bcolumns], + datatype: dt }); + // workspace + var x = values ? [] : undefined; + // vector with marks indicating a value x[i] exists in a given column + var w = []; + // variables + var ka, ka0, ka1, kb, kb0, kb1, ia, ib; + // loop b columns + for (var jb = 0; jb < bcolumns; jb++) { + // update ptr + cptr[jb] = cindex.length; + // mark in workspace for current column + var mark = jb + 1; + // B values & index in j + for (kb0 = bptr[jb], kb1 = bptr[jb + 1], kb = kb0; kb < kb1; kb++) { + // b row + ib = bindex[kb]; + // check we need to process values + if (values) { + // loop values in a[:,ib] + for (ka0 = aptr[ib], ka1 = aptr[ib + 1], ka = ka0; ka < ka1; ka++) { + // row + ia = aindex[ka]; + // check value exists in current j + if (w[ia] !== mark) { + // ia is new entry in j + w[ia] = mark; + // add i to pattern of C + cindex.push(ia); + // x(ia) = A + x[ia] = mf(bvalues[kb], avalues[ka]); + } + else { + // i exists in C already + x[ia] = af(x[ia], mf(bvalues[kb], avalues[ka])); + } + } + } + else { + // loop values in a[:,ib] + for (ka0 = aptr[ib], ka1 = aptr[ib + 1], ka = ka0; ka < ka1; ka++) { + // row + ia = aindex[ka]; + // check value exists in current j + if (w[ia] !== mark) { + // ia is new entry in j + w[ia] = mark; + // add i to pattern of C + cindex.push(ia); + } + } + } + } + // check we need to process matrix values (pattern matrix) + if (values) { + // copy values from x to column jb of c + for (var p0 = cptr[jb], p1 = cindex.length, p = p0; p < p1; p++) { + // row + var ic = cindex[p]; + // copy value + cvalues[p] = x[ic]; + } + } + } + // update ptr + cptr[bcolumns] = cindex.length; + + // check we need to squeeze the result into a scalar + if (arows === 1 && bcolumns === 1 && values) + return cvalues.length === 1 ? cvalues[0] : 0; + + // return sparse matrix + return c; }; return multiply; diff --git a/lib/function/arithmetic/multiplyScalar.js b/lib/function/arithmetic/multiplyScalar.js new file mode 100644 index 000000000..bf687ebf9 --- /dev/null +++ b/lib/function/arithmetic/multiplyScalar.js @@ -0,0 +1,52 @@ +'use strict'; + +function factory(type, config, load, typed) { + + /** + * Multiply two scalar values, `x * y`. + * This function is meant for internal use: it is used by the public function + * `multiply` + * + * This function does not support collections (Array or Matrix), and does + * not validate the number of of inputs. + * + * @param {Number | BigNumber | Boolean | Complex | Unit | null} x First value to multiply + * @param {Number | BigNumber | Boolean | Complex | null} y Second value to multiply + * @return {Number | BigNumber | Complex | Unit} Multiplication of `x` and `y` + * @private + */ + var multiplyScalar = typed('multiplyScalar', { + + 'number, number': function (x, y) { + return x * y; + }, + + 'Complex, Complex': function (x, y) { + return new type.Complex( + x.re * y.re - x.im * y.im, + x.re * y.im + x.im * y.re + ); + }, + + 'BigNumber, BigNumber': function (x, y) { + return x.times(y); + }, + + 'number, Unit': function (x, y) { + var res = y.clone(); + res.value = (res.value === null) ? res._normalize(x) : (res.value * x); + return res; + }, + + 'Unit, number': function (x, y) { + var res = x.clone(); + res.value = (res.value === null) ? res._normalize(y) : (res.value * y); + return res; + }, + }); + + return multiplyScalar; +} + +exports.name = 'multiplyScalar'; +exports.factory = factory; diff --git a/lib/function/arithmetic/norm.js b/lib/function/arithmetic/norm.js index c89eca60d..223def388 100644 --- a/lib/function/arithmetic/norm.js +++ b/lib/function/arithmetic/norm.js @@ -2,17 +2,17 @@ function factory (type, config, load, typed) { - var abs = load(require('../arithmetic/abs')); - var add = load(require('../arithmetic/add')); - var pow = load(require('../arithmetic/pow')); - var sqrt = load(require('../arithmetic/sqrt')); - var multiply = load(require('../arithmetic/multiply')); - var equal = load(require('../relational/equal')); - var larger = load(require('../relational/larger')); - var smaller = load(require('../relational/smaller')); - var matrix = load(require('../construction/matrix')); - var trace = load(require('../matrix/trace')); - var transpose = load(require('../matrix/transpose')); + var abs = load(require('../arithmetic/abs')); + var add = load(require('../arithmetic/add')); + var pow = load(require('../arithmetic/pow')); + var sqrt = load(require('../arithmetic/sqrt')); + var multiply = load(require('../arithmetic/multiply')); + var equalScalar = load(require('../relational/equalScalar')); + var larger = load(require('../relational/larger')); + var smaller = load(require('../relational/smaller')); + var matrix = load(require('../construction/matrix')); + var trace = load(require('../matrix/trace')); + var transpose = load(require('../matrix/transpose')); var complexAbs = abs.signatures['Complex']; @@ -136,7 +136,7 @@ function factory (type, config, load, typed) { } if (typeof p === 'number' && !isNaN(p)) { // check p != 0 - if (!equal(p, 0)) { + if (!equalScalar(p, 0)) { // norm(x, p) = sum(abs(xi) ^ p) ^ 1/p var n = 0; // skip zeros since abs(0) == 0 diff --git a/lib/function/arithmetic/nthRoot.js b/lib/function/arithmetic/nthRoot.js index be748d79f..8354b5e15 100644 --- a/lib/function/arithmetic/nthRoot.js +++ b/lib/function/arithmetic/nthRoot.js @@ -1,8 +1,16 @@ 'use strict'; function factory (type, config, load, typed) { - var collection = load(require('../../type/collection')); + var matrix = load(require('../construction/matrix')); + + var algorithm01 = load(require('../../type/matrix/util/algorithm01')); + var algorithm02 = load(require('../../type/matrix/util/algorithm02')); + var algorithm06 = load(require('../../type/matrix/util/algorithm06')); + var algorithm11 = load(require('../../type/matrix/util/algorithm11')); + var algorithm13 = load(require('../../type/matrix/util/algorithm13')); + var algorithm14 = load(require('../../type/matrix/util/algorithm14')); + /** * Calculate the nth root of a value. * The principal nth root of a positive real number A, is the positive real @@ -33,6 +41,7 @@ function factory (type, config, load, typed) { * @return {Number | Complex | Array | Matrix} Returns the nth root of `a` */ var nthRoot = typed('nthRoot', { + 'number': function (x) { return _nthRoot(x, 2); }, @@ -44,15 +53,118 @@ function factory (type, config, load, typed) { 'BigNumber, BigNumber': _bigNthRoot, 'Array | Matrix': function (x) { - return collection.deepMap(x, nthRoot); + return nthRoot(x, 2); + }, + + 'Matrix, Matrix': function (x, y) { + // result + var c; + + // process matrix storage + switch (x.storage()) { + case 'sparse': + switch (y.storage()) { + case 'sparse': + // density must be one (no zeros in matrix) + if (y.density() === 1) { + // sparse + sparse + c = algorithm06(x, y, nthRoot); + } + else { + // throw exception + throw new Error('Root must be non-zero'); + } + break; + default: + // sparse + dense + c = algorithm02(y, x, nthRoot, true); + break; + } + break; + default: + switch (y.storage()) { + case 'sparse': + // density must be one (no zeros in matrix) + if (y.density() === 1) { + // dense + sparse + c = algorithm01(x, y, nthRoot, false); + } + else { + // throw exception + throw new Error('Root must be non-zero'); + } + break; + default: + // dense + dense + c = algorithm13(x, y, nthRoot); + break; + } + break; + } + return c; }, - 'Array | Matrix, any': function (x, root) { - return collection.deepMap2(x, root, nthRoot); + 'Array, Array': function (x, y) { + // use matrix implementation + return nthRoot(matrix(x), matrix(y)).valueOf(); }, - 'any, Array | Matrix': function (x, root) { - return collection.deepMap2(x, root, nthRoot); + 'Array, Matrix': function (x, y) { + // use matrix implementation + return nthRoot(matrix(x), y); + }, + + 'Matrix, Array': function (x, y) { + // use matrix implementation + return nthRoot(x, matrix(y)); + }, + + 'Matrix, number | BigNumber': function (x, y) { + // result + var c; + // check storage format + switch (x.storage()) { + case 'sparse': + c = algorithm11(x, y, nthRoot, false); + break; + default: + c = algorithm14(x, y, nthRoot, false); + break; + } + return c; + }, + + 'number | BigNumber, Matrix': function (x, y) { + // result + var c; + // check storage format + switch (y.storage()) { + case 'sparse': + // density must be one (no zeros in matrix) + if (y.density() === 1) { + // sparse - scalar + c = algorithm11(y, x, nthRoot, true); + } + else { + // throw exception + throw new Error('Root must be non-zero'); + } + break; + default: + c = algorithm14(y, x, nthRoot, true); + break; + } + return c; + }, + + 'Array, number | BigNumber': function (x, y) { + // use matrix implementation + return nthRoot(matrix(x), y).valueOf(); + }, + + 'number | BigNumber, Array': function (x, y) { + // use matrix implementation + return nthRoot(x, matrix(y)).valueOf(); } }); diff --git a/lib/function/arithmetic/round.js b/lib/function/arithmetic/round.js index 194677fb9..8eb2faa2f 100644 --- a/lib/function/arithmetic/round.js +++ b/lib/function/arithmetic/round.js @@ -4,8 +4,16 @@ var isInteger = require('../../util/number').isInteger; var toFixed = require('../../util/number').toFixed; function factory (type, config, load, typed) { - var collection = load(require('../../type/collection')); + var collection = load(require('../../type/collection')); + var matrix = load(require('../construction/matrix')); + var equalScalar = load(require('../relational/equalScalar')); + var zeros = load(require('../matrix/zeros')); + + var algorithm11 = load(require('../../type/matrix/util/algorithm11')); + var algorithm12 = load(require('../../type/matrix/util/algorithm12')); + var algorithm14 = load(require('../../type/matrix/util/algorithm14')); + /** * Round a value towards the nearest integer. * For matrices, the function is evaluated element wise. @@ -38,6 +46,7 @@ function factory (type, config, load, typed) { * @return {Number | BigNumber | Complex | Array | Matrix} Rounded value */ var round = typed('round', { + 'number': Math.round, 'number, number': function (x, n) { @@ -84,12 +93,49 @@ function factory (type, config, load, typed) { return collection.deepMap(x, round, true); }, - 'Array | Matrix, number | BigNumber': function (x, n) { - return collection.deepMap2(x, n, round); + 'Matrix, number | BigNumber': function (x, y) { + // result + var c; + // check storage format + switch (x.storage()) { + case 'sparse': + c = algorithm11(x, y, round, false); + break; + default: + c = algorithm14(x, y, round, false); + break; + } + return c; }, - 'number | Complex | BigNumber, Array | Matrix': function (x, n) { - return collection.deepMap2(x, n, round); + 'number | Complex | BigNumber, Matrix': function (x, y) { + // check scalar is zero + if (!equalScalar(x, 0)) { + // result + var c; + // check storage format + switch (y.storage()) { + case 'sparse': + c = algorithm12(y, x, round, true); + break; + default: + c = algorithm14(y, x, round, true); + break; + } + return c; + } + // do not execute algorithm, result will be a zero matrix + return zeros(y.size(), y.storage()); + }, + + 'Array, number | BigNumber': function (x, y) { + // use matrix implementation + return algorithm14(matrix(x), y, round, false).valueOf(); + }, + + 'number | Complex | BigNumber, Array': function (x, y) { + // use matrix implementation + return algorithm14(matrix(y), x, round, true).valueOf(); } }); diff --git a/lib/function/arithmetic/subtract.js b/lib/function/arithmetic/subtract.js index 29bb1a1ff..aa5bc51fe 100644 --- a/lib/function/arithmetic/subtract.js +++ b/lib/function/arithmetic/subtract.js @@ -1,7 +1,19 @@ 'use strict'; +var DimensionError = require('../../error/DimensionError'); + function factory (type, config, load, typed) { - var collection = load(require('../../type/collection')); + + var matrix = load(require('../construction/matrix')); + var addScalar = load(require('./addScalar')); + var unaryMinus = load(require('./unaryMinus')); + + var algorithm01 = load(require('../../type/matrix/util/algorithm01')); + var algorithm03 = load(require('../../type/matrix/util/algorithm03')); + var algorithm05 = load(require('../../type/matrix/util/algorithm05')); + var algorithm10 = load(require('../../type/matrix/util/algorithm10')); + var algorithm13 = load(require('../../type/matrix/util/algorithm13')); + var algorithm14 = load(require('../../type/matrix/util/algorithm14')); /** * Subtract two values, `x - y`. @@ -37,6 +49,7 @@ function factory (type, config, load, typed) { * Subtraction of `x` and `y` */ var subtract = typed('subtract', { + 'number, number': function (x, y) { return x - y; }, @@ -71,13 +84,103 @@ function factory (type, config, load, typed) { return res; }, + + 'Matrix, Matrix': function (x, y) { + // matrix sizes + var xsize = x.size(); + var ysize = y.size(); - 'Array | Matrix, any': function (x, y) { - return collection.deepMap2(x, y, subtract); + // check dimensions + if (xsize.length !== ysize.length) + throw new DimensionError(xsize.length, ysize.length); + + // result + var c; + + // process matrix storage + switch (x.storage()) { + case 'sparse': + switch (y.storage()) { + case 'sparse': + // sparse - sparse + c = algorithm05(x, y, subtract); + break; + default: + // sparse - dense + c = algorithm03(y, x, subtract, true); + break; + } + break; + default: + switch (y.storage()) { + case 'sparse': + // dense - sparse + c = algorithm01(x, y, subtract, false); + break; + default: + // dense - dense + c = algorithm13(x, y, subtract); + break; + } + break; + } + return c; + }, + + 'Array, Array': function (x, y) { + // use matrix implementation + return subtract(matrix(x), matrix(y)).valueOf(); }, - 'any, Array | Matrix': function (x, y) { - return collection.deepMap2(x, y, subtract); + 'Array, Matrix': function (x, y) { + // use matrix implementation + return subtract(matrix(x), y); + }, + + 'Matrix, Array': function (x, y) { + // use matrix implementation + return subtract(x, matrix(y)); + }, + + 'Matrix, any': function (x, y) { + // result + var c; + // check storage format + switch (x.storage()) { + case 'sparse': + // algorithm 7 is faster than 9 since it calls f() for nonzero items only! + c = algorithm10(x, unaryMinus(y), addScalar); + break; + default: + c = algorithm14(x, y, subtract); + break; + } + return c; + }, + + 'any, Matrix': function (x, y) { + // result + var c; + // check storage format + switch (y.storage()) { + case 'sparse': + c = algorithm10(y, x, subtract, true); + break; + default: + c = algorithm14(y, x, subtract, true); + break; + } + return c; + }, + + 'Array, any': function (x, y) { + // use matrix implementation + return algorithm14(matrix(x), y, subtract, false).valueOf(); + }, + + 'any, Array': function (x, y) { + // use matrix implementation + return algorithm14(matrix(y), x, subtract, true).valueOf(); } }); diff --git a/lib/function/bitwise/bitAnd.js b/lib/function/bitwise/bitAnd.js index 978e68489..84a33f32f 100644 --- a/lib/function/bitwise/bitAnd.js +++ b/lib/function/bitwise/bitAnd.js @@ -4,8 +4,15 @@ var isInteger = require('../../util/number').isInteger; var bigBitAnd = require('../../util/bignumber').and; function factory (type, config, load, typed) { - var collection = load(require('../../type/collection')); + var matrix = load(require('../construction/matrix')); + + var algorithm02 = load(require('../../type/matrix/util/algorithm02')); + var algorithm06 = load(require('../../type/matrix/util/algorithm06')); + var algorithm11 = load(require('../../type/matrix/util/algorithm11')); + var algorithm13 = load(require('../../type/matrix/util/algorithm13')); + var algorithm14 = load(require('../../type/matrix/util/algorithm14')); + /** * Bitwise AND two values, `x & y`. * For matrices, the function is evaluated element wise. @@ -29,6 +36,7 @@ function factory (type, config, load, typed) { * @return {Number | BigNumber | Array | Matrix} AND of `x` and `y` */ var bitAnd = typed('bitAnd', { + 'number, number': function (x, y) { if (!isInteger(x) || !isInteger(y)) { throw new Error('Integers expected in function bitAnd'); @@ -39,12 +47,93 @@ function factory (type, config, load, typed) { 'BigNumber, BigNumber': bigBitAnd, - 'Array | Matrix, any': function (x, y) { - return collection.deepMap2(x, y, bitAnd); + 'Matrix, Matrix': function (x, y) { + // result + var c; + + // process matrix storage + switch (x.storage()) { + case 'sparse': + switch (y.storage()) { + case 'sparse': + // sparse & sparse + c = algorithm06(x, y, bitAnd, false); + break; + default: + // sparse & dense + c = algorithm02(y, x, bitAnd, true); + break; + } + break; + default: + switch (y.storage()) { + case 'sparse': + // dense & sparse + c = algorithm02(x, y, bitAnd, false); + break; + default: + // dense & dense + c = algorithm13(x, y, bitAnd); + break; + } + break; + } + return c; + }, + + 'Array, Array': function (x, y) { + // use matrix implementation + return bitAnd(matrix(x), matrix(y)).valueOf(); }, - 'any, Array | Matrix': function (x, y) { - return collection.deepMap2(x, y, bitAnd); + 'Array, Matrix': function (x, y) { + // use matrix implementation + return bitAnd(matrix(x), y); + }, + + 'Matrix, Array': function (x, y) { + // use matrix implementation + return bitAnd(x, matrix(y)); + }, + + 'Matrix, any': function (x, y) { + // result + var c; + // check storage format + switch (x.storage()) { + case 'sparse': + c = algorithm11(x, y, bitAnd, false); + break; + default: + c = algorithm14(x, y, bitAnd, false); + break; + } + return c; + }, + + 'any, Matrix': function (x, y) { + // result + var c; + // check storage format + switch (y.storage()) { + case 'sparse': + c = algorithm11(y, x, bitAnd, true); + break; + default: + c = algorithm14(y, x, bitAnd, true); + break; + } + return c; + }, + + 'Array, any': function (x, y) { + // use matrix implementation + return algorithm14(matrix(x), y, bitAnd, false).valueOf(); + }, + + 'any, Array': function (x, y) { + // use matrix implementation + return algorithm14(matrix(y), x, bitAnd, true).valueOf(); } }); diff --git a/lib/function/bitwise/bitOr.js b/lib/function/bitwise/bitOr.js index 421bafca5..0a5e371da 100644 --- a/lib/function/bitwise/bitOr.js +++ b/lib/function/bitwise/bitOr.js @@ -4,8 +4,15 @@ var isInteger = require('../../util/number').isInteger; var bigBitOr = require('../../util/bignumber').or; function factory (type, config, load, typed) { - var collection = load(require('../../type/collection')); + var matrix = load(require('../construction/matrix')); + + var algorithm01 = load(require('../../type/matrix/util/algorithm01')); + var algorithm04 = load(require('../../type/matrix/util/algorithm04')); + var algorithm10 = load(require('../../type/matrix/util/algorithm10')); + var algorithm13 = load(require('../../type/matrix/util/algorithm13')); + var algorithm14 = load(require('../../type/matrix/util/algorithm14')); + /** * Bitwise OR two values, `x | y`. * For matrices, the function is evaluated element wise. @@ -30,6 +37,7 @@ function factory (type, config, load, typed) { * @return {Number | BigNumber | Array | Matrix} OR of `x` and `y` */ var bitOr = typed('bitOr', { + 'number, number': function (x, y) { if (!isInteger(x) || !isInteger(y)) { throw new Error('Integers expected in function bitOr'); @@ -40,12 +48,92 @@ function factory (type, config, load, typed) { 'BigNumber, BigNumber': bigBitOr, - 'Array | Matrix, any': function (x, y) { - return collection.deepMap2(x, y, bitOr); + 'Matrix, Matrix': function (x, y) { + // result + var c; + + // process matrix storage + switch (x.storage()) { + case 'sparse': + switch (y.storage()) { + case 'sparse': + // sparse + sparse + c = algorithm04(x, y, bitOr); + break; + default: + // sparse + dense + c = algorithm01(y, x, bitOr, true); + break; + } + break; + default: + switch (y.storage()) { + case 'sparse': + // dense + sparse + c = algorithm01(x, y, bitOr, false); + break; + default: + c = algorithm13(x, y, bitOr); + break; + } + break; + } + return c; }, - 'any, Array | Matrix': function (x, y) { - return collection.deepMap2(x, y, bitOr); + 'Array, Array': function (x, y) { + // use matrix implementation + return bitOr(matrix(x), matrix(y)).valueOf(); + }, + + 'Array, Matrix': function (x, y) { + // use matrix implementation + return bitOr(matrix(x), y); + }, + + 'Matrix, Array': function (x, y) { + // use matrix implementation + return bitOr(x, matrix(y)); + }, + + 'Matrix, any': function (x, y) { + // result + var c; + // check storage format + switch (x.storage()) { + case 'sparse': + c = algorithm10(x, y, bitOr, false); + break; + default: + c = algorithm14(x, y, bitOr, false); + break; + } + return c; + }, + + 'any, Matrix': function (x, y) { + // result + var c; + // check storage format + switch (y.storage()) { + case 'sparse': + c = algorithm10(y, x, bitOr, true); + break; + default: + c = algorithm14(y, x, bitOr, true); + break; + } + return c; + }, + + 'Array, any': function (x, y) { + // use matrix implementation + return algorithm14(matrix(x), y, bitOr, false).valueOf(); + }, + + 'any, Array': function (x, y) { + // use matrix implementation + return algorithm14(matrix(y), x, bitOr, true).valueOf(); } }); diff --git a/lib/function/bitwise/bitXor.js b/lib/function/bitwise/bitXor.js index 3a8d9ea6b..b54ed7a01 100644 --- a/lib/function/bitwise/bitXor.js +++ b/lib/function/bitwise/bitXor.js @@ -4,7 +4,14 @@ var isInteger = require('../../util/number').isInteger; var bigBitXor = require('../../util/bignumber').xor; function factory (type, config, load, typed) { - var collection = load(require('../../type/collection')); + + var matrix = load(require('../construction/matrix')); + + var algorithm03 = load(require('../../type/matrix/util/algorithm03')); + var algorithm07 = load(require('../../type/matrix/util/algorithm07')); + var algorithm12 = load(require('../../type/matrix/util/algorithm12')); + var algorithm13 = load(require('../../type/matrix/util/algorithm13')); + var algorithm14 = load(require('../../type/matrix/util/algorithm14')); /** * Bitwise XOR two values, `x ^ y`. @@ -29,6 +36,7 @@ function factory (type, config, load, typed) { * @return {Number | BigNumber | Array | Matrix} XOR of `x` and `y` */ var bitXor = typed('bitXor', { + 'number, number': function (x, y) { if (!isInteger(x) || !isInteger(y)) { throw new Error('Integers expected in function bitXor'); @@ -39,12 +47,93 @@ function factory (type, config, load, typed) { 'BigNumber, BigNumber': bigBitXor, - 'Array | Matrix, any': function (x, y) { - return collection.deepMap2(x, y, bitXor); + 'Matrix, Matrix': function (x, y) { + // result + var c; + + // process matrix storage + switch (x.storage()) { + case 'sparse': + switch (y.storage()) { + case 'sparse': + // sparse + sparse + c = algorithm07(x, y, bitXor); + break; + default: + // sparse + dense + c = algorithm03(y, x, bitXor, true); + break; + } + break; + default: + switch (y.storage()) { + case 'sparse': + // dense + sparse + c = algorithm03(x, y, bitXor, false); + break; + default: + // dense + dense + c = algorithm13(x, y, bitXor); + break; + } + break; + } + return c; }, - 'any, Array | Matrix': function (x, y) { - return collection.deepMap2(x, y, bitXor); + 'Array, Array': function (x, y) { + // use matrix implementation + return bitXor(matrix(x), matrix(y)).valueOf(); + }, + + 'Array, Matrix': function (x, y) { + // use matrix implementation + return bitXor(matrix(x), y); + }, + + 'Matrix, Array': function (x, y) { + // use matrix implementation + return bitXor(x, matrix(y)); + }, + + 'Matrix, any': function (x, y) { + // result + var c; + // check storage format + switch (x.storage()) { + case 'sparse': + c = algorithm12(x, y, bitXor, false); + break; + default: + c = algorithm14(x, y, bitXor, false); + break; + } + return c; + }, + + 'any, Matrix': function (x, y) { + // result + var c; + // check storage format + switch (y.storage()) { + case 'sparse': + c = algorithm12(y, x, bitXor, true); + break; + default: + c = algorithm14(y, x, bitXor, true); + break; + } + return c; + }, + + 'Array, any': function (x, y) { + // use matrix implementation + return algorithm14(matrix(x), y, bitXor, false).valueOf(); + }, + + 'any, Array': function (x, y) { + // use matrix implementation + return algorithm14(matrix(y), x, bitXor, true).valueOf(); } }); diff --git a/lib/function/bitwise/leftShift.js b/lib/function/bitwise/leftShift.js index d4a1df209..80e569f26 100644 --- a/lib/function/bitwise/leftShift.js +++ b/lib/function/bitwise/leftShift.js @@ -4,7 +4,18 @@ var isInteger = require('../../util/number').isInteger; var bigLeftShift = require('../../util/bignumber').leftShift; function factory (type, config, load, typed) { - var collection = load(require('../../type/collection')); + + var matrix = load(require('../construction/matrix')); + var equalScalar = load(require('../relational/equalScalar')); + var zeros = load(require('../matrix/zeros')); + + var algorithm01 = load(require('../../type/matrix/util/algorithm01')); + var algorithm02 = load(require('../../type/matrix/util/algorithm02')); + var algorithm08 = load(require('../../type/matrix/util/algorithm08')); + var algorithm10 = load(require('../../type/matrix/util/algorithm10')); + var algorithm11 = load(require('../../type/matrix/util/algorithm11')); + var algorithm13 = load(require('../../type/matrix/util/algorithm13')); + var algorithm14 = load(require('../../type/matrix/util/algorithm14')); /** * Bitwise left logical shift of a value x by y number of bits, `x << y`. @@ -23,13 +34,14 @@ function factory (type, config, load, typed) { * * See also: * - * bitAnd, bitNot, bitOr, bitXor, rightArithShift, rightLogShift + * leftShift, bitNot, bitOr, bitXor, rightArithShift, rightLogShift * * @param {Number | BigNumber | Boolean | Array | Matrix | null} x Value to be shifted * @param {Number | BigNumber | Boolean | null} y Amount of shifts * @return {Number | BigNumber | Array | Matrix} `x` shifted left `y` times */ var leftShift = typed('leftShift', { + 'number, number': function (x, y) { if (!isInteger(x) || !isInteger(y)) { throw new Error('Integers expected in function leftShift'); @@ -40,12 +52,101 @@ function factory (type, config, load, typed) { 'BigNumber, BigNumber': bigLeftShift, - 'Array | Matrix, any': function (x, y) { - return collection.deepMap2(x, y, leftShift); + 'Matrix, Matrix': function (x, y) { + // result + var c; + + // process matrix storage + switch (x.storage()) { + case 'sparse': + switch (y.storage()) { + case 'sparse': + // sparse & sparse + c = algorithm08(x, y, leftShift, false); + break; + default: + // sparse & dense + c = algorithm02(y, x, leftShift, true); + break; + } + break; + default: + switch (y.storage()) { + case 'sparse': + // dense & sparse + c = algorithm01(x, y, leftShift, false); + break; + default: + // dense & dense + c = algorithm13(x, y, leftShift); + break; + } + break; + } + return c; }, - 'any, Array | Matrix': function (x, y) { - return collection.deepMap2(x, y, leftShift); + 'Array, Array': function (x, y) { + // use matrix implementation + return leftShift(matrix(x), matrix(y)).valueOf(); + }, + + 'Array, Matrix': function (x, y) { + // use matrix implementation + return leftShift(matrix(x), y); + }, + + 'Matrix, Array': function (x, y) { + // use matrix implementation + return leftShift(x, matrix(y)); + }, + + 'Matrix, number | BigNumber': function (x, y) { + // check scalar + if (!equalScalar(y, 0)) { + // result + var c; + // check storage format + switch (x.storage()) { + case 'sparse': + c = algorithm11(x, y, leftShift, false); + break; + default: + c = algorithm14(x, y, leftShift, false); + break; + } + return c; + } + return x.clone(); + }, + + 'number | BigNumber, Matrix': function (x, y) { + // check scalar + if (!equalScalar(x, 0)) { + // result + var c; + // check storage format + switch (y.storage()) { + case 'sparse': + c = algorithm10(y, x, leftShift, true); + break; + default: + c = algorithm14(y, x, leftShift, true); + break; + } + return c; + } + return zeros(y.size(), y.storage()); + }, + + 'Array, number | BigNumber': function (x, y) { + // use matrix implementation + return leftShift(matrix(x), y).valueOf(); + }, + + 'number | BigNumber, Array': function (x, y) { + // use matrix implementation + return leftShift(x, matrix(y)).valueOf(); } }); diff --git a/lib/function/bitwise/rightArithShift.js b/lib/function/bitwise/rightArithShift.js index 51f376939..7ea7f7d37 100644 --- a/lib/function/bitwise/rightArithShift.js +++ b/lib/function/bitwise/rightArithShift.js @@ -4,7 +4,18 @@ var isInteger = require('../../util/number').isInteger; var bigRightArithShift = require('../../util/bignumber').rightArithShift; function factory (type, config, load, typed) { - var collection = load(require('../../type/collection')); + + var matrix = load(require('../construction/matrix')); + var equalScalar = load(require('../relational/equalScalar')); + var zeros = load(require('../matrix/zeros')); + + var algorithm01 = load(require('../../type/matrix/util/algorithm01')); + var algorithm02 = load(require('../../type/matrix/util/algorithm02')); + var algorithm08 = load(require('../../type/matrix/util/algorithm08')); + var algorithm10 = load(require('../../type/matrix/util/algorithm10')); + var algorithm11 = load(require('../../type/matrix/util/algorithm11')); + var algorithm13 = load(require('../../type/matrix/util/algorithm13')); + var algorithm14 = load(require('../../type/matrix/util/algorithm14')); /** * Bitwise right arithmetic shift of a value x by y number of bits, `x >> y`. @@ -23,13 +34,14 @@ function factory (type, config, load, typed) { * * See also: * - * bitAnd, bitNot, bitOr, bitXor, leftShift, rightLogShift + * bitAnd, bitNot, bitOr, bitXor, rightArithShift, rightLogShift * * @param {Number | BigNumber | Boolean | Array | Matrix | null} x Value to be shifted * @param {Number | BigNumber | Boolean | null} y Amount of shifts * @return {Number | BigNumber | Array | Matrix} `x` sign-filled shifted right `y` times */ var rightArithShift = typed('rightArithShift', { + 'number, number': function (x, y) { if (!isInteger(x) || !isInteger(y)) { throw new Error('Integers expected in function rightArithShift'); @@ -40,12 +52,101 @@ function factory (type, config, load, typed) { 'BigNumber, BigNumber': bigRightArithShift, - 'Array | Matrix, any': function (x, y) { - return collection.deepMap2(x, y, rightArithShift); + 'Matrix, Matrix': function (x, y) { + // result + var c; + + // process matrix storage + switch (x.storage()) { + case 'sparse': + switch (y.storage()) { + case 'sparse': + // sparse & sparse + c = algorithm08(x, y, rightArithShift, false); + break; + default: + // sparse & dense + c = algorithm02(y, x, rightArithShift, true); + break; + } + break; + default: + switch (y.storage()) { + case 'sparse': + // dense & sparse + c = algorithm01(x, y, rightArithShift, false); + break; + default: + // dense & dense + c = algorithm13(x, y, rightArithShift); + break; + } + break; + } + return c; }, - 'any, Array | Matrix': function (x, y) { - return collection.deepMap2(x, y, rightArithShift); + 'Array, Array': function (x, y) { + // use matrix implementation + return rightArithShift(matrix(x), matrix(y)).valueOf(); + }, + + 'Array, Matrix': function (x, y) { + // use matrix implementation + return rightArithShift(matrix(x), y); + }, + + 'Matrix, Array': function (x, y) { + // use matrix implementation + return rightArithShift(x, matrix(y)); + }, + + 'Matrix, number | BigNumber': function (x, y) { + // check scalar + if (!equalScalar(y, 0)) { + // result + var c; + // check storage format + switch (x.storage()) { + case 'sparse': + c = algorithm11(x, y, rightArithShift, false); + break; + default: + c = algorithm14(x, y, rightArithShift, false); + break; + } + return c; + } + return x.clone(); + }, + + 'number | BigNumber, Matrix': function (x, y) { + // check scalar + if (!equalScalar(x, 0)) { + // result + var c; + // check storage format + switch (y.storage()) { + case 'sparse': + c = algorithm10(y, x, rightArithShift, true); + break; + default: + c = algorithm14(y, x, rightArithShift, true); + break; + } + return c; + } + return zeros(y.size(), y.storage()); + }, + + 'Array, number | BigNumber': function (x, y) { + // use matrix implementation + return rightArithShift(matrix(x), y).valueOf(); + }, + + 'number | BigNumber, Array': function (x, y) { + // use matrix implementation + return rightArithShift(x, matrix(y)).valueOf(); } }); diff --git a/lib/function/bitwise/rightLogShift.js b/lib/function/bitwise/rightLogShift.js index b870ee9f6..b426e7b56 100644 --- a/lib/function/bitwise/rightLogShift.js +++ b/lib/function/bitwise/rightLogShift.js @@ -3,8 +3,19 @@ var isInteger = require('../../util/number').isInteger; function factory (type, config, load, typed) { - var collection = load(require('../../type/collection')); + var matrix = load(require('../construction/matrix')); + var equalScalar = load(require('../relational/equalScalar')); + var zeros = load(require('../matrix/zeros')); + + var algorithm01 = load(require('../../type/matrix/util/algorithm01')); + var algorithm02 = load(require('../../type/matrix/util/algorithm02')); + var algorithm08 = load(require('../../type/matrix/util/algorithm08')); + var algorithm10 = load(require('../../type/matrix/util/algorithm10')); + var algorithm11 = load(require('../../type/matrix/util/algorithm11')); + var algorithm13 = load(require('../../type/matrix/util/algorithm13')); + var algorithm14 = load(require('../../type/matrix/util/algorithm14')); + /** * Bitwise right logical shift of value x by y number of bits, `x >>> y`. * For matrices, the function is evaluated element wise. @@ -22,7 +33,7 @@ function factory (type, config, load, typed) { * * See also: * - * bitAnd, bitNot, bitOr, bitXor, leftShift, rightArithShift + * bitAnd, bitNot, bitOr, bitXor, leftShift, rightLogShift * * @param {Number | Boolean | Array | Matrix | null} x Value to be shifted * @param {Number | Boolean | null} y Amount of shifts @@ -30,6 +41,7 @@ function factory (type, config, load, typed) { */ var rightLogShift = typed('rightLogShift', { + 'number, number': function (x, y) { if (!isInteger(x) || !isInteger(y)) { throw new Error('Integers expected in function rightLogShift'); @@ -40,12 +52,101 @@ function factory (type, config, load, typed) { // 'BigNumber, BigNumber': ..., // TODO: implement BigNumber support for rightLogShift - 'Array | Matrix, any': function (x, y) { - return collection.deepMap2(x, y, rightLogShift); + 'Matrix, Matrix': function (x, y) { + // result + var c; + + // process matrix storage + switch (x.storage()) { + case 'sparse': + switch (y.storage()) { + case 'sparse': + // sparse & sparse + c = algorithm08(x, y, rightLogShift, false); + break; + default: + // sparse & dense + c = algorithm02(y, x, rightLogShift, true); + break; + } + break; + default: + switch (y.storage()) { + case 'sparse': + // dense & sparse + c = algorithm01(x, y, rightLogShift, false); + break; + default: + // dense & dense + c = algorithm13(x, y, rightLogShift); + break; + } + break; + } + return c; }, - 'any, Array | Matrix': function (x, y) { - return collection.deepMap2(x, y, rightLogShift); + 'Array, Array': function (x, y) { + // use matrix implementation + return rightLogShift(matrix(x), matrix(y)).valueOf(); + }, + + 'Array, Matrix': function (x, y) { + // use matrix implementation + return rightLogShift(matrix(x), y); + }, + + 'Matrix, Array': function (x, y) { + // use matrix implementation + return rightLogShift(x, matrix(y)); + }, + + 'Matrix, number | BigNumber': function (x, y) { + // check scalar + if (!equalScalar(y, 0)) { + // result + var c; + // check storage format + switch (x.storage()) { + case 'sparse': + c = algorithm11(x, y, rightLogShift, false); + break; + default: + c = algorithm14(x, y, rightLogShift, false); + break; + } + return c; + } + return x.clone(); + }, + + 'number | BigNumber, Matrix': function (x, y) { + // check scalar + if (!equalScalar(x, 0)) { + // result + var c; + // check storage format + switch (y.storage()) { + case 'sparse': + c = algorithm10(y, x, rightLogShift, true); + break; + default: + c = algorithm14(y, x, rightLogShift, true); + break; + } + return c; + } + return zeros(y.size(), y.storage()); + }, + + 'Array, number | BigNumber': function (x, y) { + // use matrix implementation + return rightLogShift(matrix(x), y).valueOf(); + }, + + 'number | BigNumber, Array': function (x, y) { + // use matrix implementation + return rightLogShift(x, matrix(y)).valueOf(); } }); diff --git a/lib/function/construction/matrix.js b/lib/function/construction/matrix.js index 368060170..dfde5a981 100644 --- a/lib/function/construction/matrix.js +++ b/lib/function/construction/matrix.js @@ -9,11 +9,12 @@ function factory (type, config, load, typed) { * * Syntax: * - * math.matrix() // creates an empty matrix using default storage format (dense). - * math.matrix(data) // creates a matrix with initial data using default storage format (dense). - * math.matrix('dense') // creates an empty matrix using the given storage format. - * math.matrix(data, 'dense') // creates a matrix with initial data using the given storage format. - * math.matrix(data, 'sparse') // creates a sparse matrix with initial data. + * math.matrix() // creates an empty matrix using default storage format (dense). + * math.matrix(data) // creates a matrix with initial data using default storage format (dense). + * math.matrix('dense') // creates an empty matrix using the given storage format. + * math.matrix(data, 'dense') // creates a matrix with initial data using the given storage format. + * math.matrix(data, 'sparse') // creates a sparse matrix with initial data. + * math.matrix(data, 'sparse', 'number') // creates a sparse matrix with initial data, number data type. * * Examples: * @@ -40,31 +41,38 @@ function factory (type, config, load, typed) { 'string': function (format) { return _create([], format); }, + + 'string, string': function (format, datatype) { + return _create([], format, datatype); + }, 'Array': function (data) { return _create(data); }, - + 'Matrix': function (data) { return _create(data, data.storage()); }, - 'Array | Matrix, string': _create + 'Array | Matrix, string': _create, + + 'Array | Matrix, string, string': _create }); /** * Create a new Matrix with given storage format * @param {Array} data * @param {string} [format] + * @param {string} [datatype] * @returns {Matrix} Returns a new Matrix * @private */ - function _create(data, format) { + function _create(data, format, datatype) { // get storage format constructor var M = type.Matrix.storage(format || 'default'); // create instance - return new M(data); + return new M(data, datatype); } } diff --git a/lib/function/construction/sparse.js b/lib/function/construction/sparse.js index f7a6c3b5c..71c9fba6a 100644 --- a/lib/function/construction/sparse.js +++ b/lib/function/construction/sparse.js @@ -13,6 +13,7 @@ function factory (type, config, load, typed) { * * math.sparse() // creates an empty sparse matrix. * math.sparse(data) // creates a sparse matrix with initial data. + * math.sparse(data, 'number') // creates a sparse matrix with initial data, number datatype. * * Examples: * @@ -34,9 +35,17 @@ function factory (type, config, load, typed) { '': function () { return new SparseMatrix([]); }, + + 'string': function (datatype) { + return new SparseMatrix([], datatype); + }, 'Array | Matrix': function (data) { return new SparseMatrix(data); + }, + + 'Array | Matrix, string': function (data, datatype) { + return new SparseMatrix(data, datatype); } }); } diff --git a/lib/function/logical/and.js b/lib/function/logical/and.js index ffd2b9c57..4822e5a84 100644 --- a/lib/function/logical/and.js +++ b/lib/function/logical/and.js @@ -1,7 +1,16 @@ 'use strict'; function factory (type, config, load, typed) { - var collection = load(require('../../type/collection')); + + var matrix = load(require('../construction/matrix')); + var zeros = load(require('../matrix/zeros')); + var not = load(require('./not')); + + var algorithm02 = load(require('../../type/matrix/util/algorithm02')); + var algorithm06 = load(require('../../type/matrix/util/algorithm06')); + var algorithm11 = load(require('../../type/matrix/util/algorithm11')); + var algorithm13 = load(require('../../type/matrix/util/algorithm13')); + var algorithm14 = load(require('../../type/matrix/util/algorithm14')); /** * Logical `and`. Test whether two values are both defined with a nonzero/nonempty value. @@ -32,6 +41,7 @@ function factory (type, config, load, typed) { * Returns true when both inputs are defined with a nonzero/nonempty value. */ var and = typed('and', { + 'number, number': function (x, y) { return !!(x && y); }, @@ -47,13 +57,104 @@ function factory (type, config, load, typed) { 'Unit, Unit': function (x, y) { return (x.value !== 0 && x.value !== null) && (y.value !== 0 && y.value !== null); }, + + 'Matrix, Matrix': function (x, y) { + // result + var c; - 'Array | Matrix, any': function (x, y) { - return collection.deepMap2(x, y, and); + // process matrix storage + switch (x.storage()) { + case 'sparse': + switch (y.storage()) { + case 'sparse': + // sparse & sparse + c = algorithm06(x, y, and, false); + break; + default: + // sparse & dense + c = algorithm02(y, x, and, true); + break; + } + break; + default: + switch (y.storage()) { + case 'sparse': + // dense & sparse + c = algorithm02(x, y, and, false); + break; + default: + // dense & dense + c = algorithm13(x, y, and); + break; + } + break; + } + return c; }, - 'any, Array | Matrix': function (x, y) { - return collection.deepMap2(x, y, and); + 'Array, Array': function (x, y) { + // use matrix implementation + return and(matrix(x), matrix(y)).valueOf(); + }, + + 'Array, Matrix': function (x, y) { + // use matrix implementation + return and(matrix(x), y); + }, + + 'Matrix, Array': function (x, y) { + // use matrix implementation + return and(x, matrix(y)); + }, + + 'Matrix, any': function (x, y) { + // check scalar + if (not(y)) { + // return zero matrix + return zeros(x.size(), x.storage()); + } + // result + var c; + // check storage format + switch (x.storage()) { + case 'sparse': + c = algorithm11(x, y, and, false); + break; + default: + c = algorithm14(x, y, and, false); + break; + } + return c; + }, + + 'any, Matrix': function (x, y) { + // check scalar + if (not(x)) { + // return zero matrix + return zeros(x.size(), x.storage()); + } + // result + var c; + // check storage format + switch (y.storage()) { + case 'sparse': + c = algorithm11(y, x, and, true); + break; + default: + c = algorithm14(y, x, and, true); + break; + } + return c; + }, + + 'Array, any': function (x, y) { + // use matrix implementation + return and(matrix(x), y).valueOf(); + }, + + 'any, Array': function (x, y) { + // use matrix implementation + return and(x, matrix(y)).valueOf(); } }); diff --git a/lib/function/logical/or.js b/lib/function/logical/or.js index 150721f73..04f3e7416 100644 --- a/lib/function/logical/or.js +++ b/lib/function/logical/or.js @@ -1,8 +1,15 @@ 'use strict'; function factory (type, config, load, typed) { - var collection = load(require('../../type/collection')); + var matrix = load(require('../construction/matrix')); + + var algorithm03 = load(require('../../type/matrix/util/algorithm03')); + var algorithm05 = load(require('../../type/matrix/util/algorithm05')); + var algorithm12 = load(require('../../type/matrix/util/algorithm12')); + var algorithm13 = load(require('../../type/matrix/util/algorithm13')); + var algorithm14 = load(require('../../type/matrix/util/algorithm14')); + /** * Logical `or`. Test if at least one value is defined with a nonzero/nonempty value. * For matrices, the function is evaluated element wise. @@ -32,6 +39,7 @@ function factory (type, config, load, typed) { * Returns true when one of the inputs is defined with a nonzero/nonempty value. */ var or = typed('or', { + 'number, number': function (x, y) { return !!(x || y); }, @@ -48,12 +56,93 @@ function factory (type, config, load, typed) { return (x.value !== 0 && x.value !== null) || (y.value !== 0 && y.value !== null); }, - 'Array | Matrix, any': function (x, y) { - return collection.deepMap2(x, y, or); + 'Matrix, Matrix': function (x, y) { + // result + var c; + + // process matrix storage + switch (x.storage()) { + case 'sparse': + switch (y.storage()) { + case 'sparse': + // sparse + sparse + c = algorithm05(x, y, or); + break; + default: + // sparse + dense + c = algorithm03(y, x, or, true); + break; + } + break; + default: + switch (y.storage()) { + case 'sparse': + // dense + sparse + c = algorithm03(x, y, or, false); + break; + default: + // dense + dense + c = algorithm13(x, y, or); + break; + } + break; + } + return c; }, - 'any, Array | Matrix': function (x, y) { - return collection.deepMap2(x, y, or); + 'Array, Array': function (x, y) { + // use matrix implementation + return or(matrix(x), matrix(y)).valueOf(); + }, + + 'Array, Matrix': function (x, y) { + // use matrix implementation + return or(matrix(x), y); + }, + + 'Matrix, Array': function (x, y) { + // use matrix implementation + return or(x, matrix(y)); + }, + + 'Matrix, any': function (x, y) { + // result + var c; + // check storage format + switch (x.storage()) { + case 'sparse': + c = algorithm12(x, y, or, false); + break; + default: + c = algorithm14(x, y, or, false); + break; + } + return c; + }, + + 'any, Matrix': function (x, y) { + // result + var c; + // check storage format + switch (y.storage()) { + case 'sparse': + c = algorithm12(y, x, or, true); + break; + default: + c = algorithm14(y, x, or, true); + break; + } + return c; + }, + + 'Array, any': function (x, y) { + // use matrix implementation + return algorithm14(matrix(x), y, or, false).valueOf(); + }, + + 'any, Array': function (x, y) { + // use matrix implementation + return algorithm14(matrix(y), x, or, true).valueOf(); } }); diff --git a/lib/function/logical/xor.js b/lib/function/logical/xor.js index fec658414..7429c590e 100644 --- a/lib/function/logical/xor.js +++ b/lib/function/logical/xor.js @@ -1,8 +1,15 @@ 'use strict'; function factory (type, config, load, typed) { - var collection = load(require('../../type/collection')); + var matrix = load(require('../construction/matrix')); + + var algorithm03 = load(require('../../type/matrix/util/algorithm03')); + var algorithm07 = load(require('../../type/matrix/util/algorithm07')); + var algorithm12 = load(require('../../type/matrix/util/algorithm12')); + var algorithm13 = load(require('../../type/matrix/util/algorithm13')); + var algorithm14 = load(require('../../type/matrix/util/algorithm14')); + /** * Logical `xor`. Test whether one and only one value is defined with a nonzero/nonempty value. * For matrices, the function is evaluated element wise. @@ -32,6 +39,7 @@ function factory (type, config, load, typed) { * Returns true when one and only one input is defined with a nonzero/nonempty value. */ var xor = typed('xor', { + 'number, number': function (x, y) { return !!(!!x ^ !!y); }, @@ -48,12 +56,93 @@ function factory (type, config, load, typed) { return !!((x.value !== 0 && x.value !== null) ^ (y.value !== 0 && y.value !== null)); }, - 'Array | Matrix, any': function (x, y) { - return collection.deepMap2(x, y, xor); + 'Matrix, Matrix': function (x, y) { + // result + var c; + + // process matrix storage + switch (x.storage()) { + case 'sparse': + switch (y.storage()) { + case 'sparse': + // sparse + sparse + c = algorithm07(x, y, xor); + break; + default: + // sparse + dense + c = algorithm03(y, x, xor, true); + break; + } + break; + default: + switch (y.storage()) { + case 'sparse': + // dense + sparse + c = algorithm03(x, y, xor, false); + break; + default: + // dense + dense + c = algorithm13(x, y, xor); + break; + } + break; + } + return c; }, - 'any, Array | Matrix': function (x, y) { - return collection.deepMap2(x, y, xor); + 'Array, Array': function (x, y) { + // use matrix implementation + return xor(matrix(x), matrix(y)).valueOf(); + }, + + 'Array, Matrix': function (x, y) { + // use matrix implementation + return xor(matrix(x), y); + }, + + 'Matrix, Array': function (x, y) { + // use matrix implementation + return xor(x, matrix(y)); + }, + + 'Matrix, any': function (x, y) { + // result + var c; + // check storage format + switch (x.storage()) { + case 'sparse': + c = algorithm12(x, y, xor, false); + break; + default: + c = algorithm14(x, y, xor, false); + break; + } + return c; + }, + + 'any, Matrix': function (x, y) { + // result + var c; + // check storage format + switch (y.storage()) { + case 'sparse': + c = algorithm12(y, x, xor, true); + break; + default: + c = algorithm14(y, x, xor, true); + break; + } + return c; + }, + + 'Array, any': function (x, y) { + // use matrix implementation + return algorithm14(matrix(x), y, xor, false).valueOf(); + }, + + 'any, Array': function (x, y) { + // use matrix implementation + return algorithm14(matrix(y), x, xor, true).valueOf(); } }); diff --git a/lib/function/matrix/diag.js b/lib/function/matrix/diag.js index 3bcd0e357..44ab8a641 100644 --- a/lib/function/matrix/diag.js +++ b/lib/function/matrix/diag.js @@ -152,7 +152,7 @@ function factory (type, config, load, typed) { // vector size var n = Math.min(s[0] - kSub, s[1] - kSuper); // diagonal values - var vector = new Array(n); + var vector = []; // loop diagonal for (var i = 0; i < n; i++) { vector[i] = clone(x[i + kSub][i + kSuper]); diff --git a/lib/function/matrix/transpose.js b/lib/function/matrix/transpose.js index b9781b17d..914d73caa 100644 --- a/lib/function/matrix/transpose.js +++ b/lib/function/matrix/transpose.js @@ -105,7 +105,8 @@ function factory (type, config, load, typed) { // return matrix return new DenseMatrix({ data: transposed, - size: [columns, rows] + size: [columns, rows], + datatype: m._datatype }); }; @@ -119,7 +120,7 @@ function factory (type, config, load, typed) { var cindex = []; var cptr = []; // row counts - var w = new Array(rows); + var w = []; for (var x = 0; x < rows; x++) w[x] = 0; // vars @@ -158,7 +159,8 @@ function factory (type, config, load, typed) { values: cvalues, index: cindex, ptr: cptr, - size: [columns, rows] + size: [columns, rows], + datatype: m._datatype }); }; diff --git a/lib/function/relational/compare.js b/lib/function/relational/compare.js index b5bd0c31d..61fe69283 100644 --- a/lib/function/relational/compare.js +++ b/lib/function/relational/compare.js @@ -3,8 +3,15 @@ var nearlyEqual = require('../../util/number').nearlyEqual; function factory (type, config, load, typed) { - var collection = load(require('../../type/collection')); + var matrix = load(require('../construction/matrix')); + + var algorithm03 = load(require('../../type/matrix/util/algorithm03')); + var algorithm05 = load(require('../../type/matrix/util/algorithm05')); + var algorithm12 = load(require('../../type/matrix/util/algorithm12')); + var algorithm13 = load(require('../../type/matrix/util/algorithm13')); + var algorithm14 = load(require('../../type/matrix/util/algorithm14')); + /** * Compare two values. Returns 1 when x > y, -1 when x < y, and 0 when x == y. * @@ -39,6 +46,7 @@ function factory (type, config, load, typed) { * @return {Number | BigNumber | Array | Matrix} Returns the result of the comparison: 1, 0 or -1. */ var compare = typed('compare', { + 'boolean, boolean': function (x, y) { return x === y ? 0 : (x > y ? 1 : -1); }, @@ -51,7 +59,7 @@ function factory (type, config, load, typed) { return new x.constructor(x.cmp(y)); }, - 'Complex, Complex': function (x, y) { + 'Complex, Complex': function () { throw new TypeError('No ordering relation is defined for complex numbers'); }, @@ -66,12 +74,93 @@ function factory (type, config, load, typed) { return x === y ? 0 : (x > y ? 1 : -1); }, - 'Array | Matrix, any': function (x, y) { - return collection.deepMap2(x, y, compare); + 'Matrix, Matrix': function (x, y) { + // result + var c; + + // process matrix storage + switch (x.storage()) { + case 'sparse': + switch (y.storage()) { + case 'sparse': + // sparse + sparse + c = algorithm05(x, y, compare); + break; + default: + // sparse + dense + c = algorithm03(y, x, compare, true); + break; + } + break; + default: + switch (y.storage()) { + case 'sparse': + // dense + sparse + c = algorithm03(x, y, compare, false); + break; + default: + // dense + dense + c = algorithm13(x, y, compare); + break; + } + break; + } + return c; }, - 'any, Array | Matrix': function (x, y) { - return collection.deepMap2(x, y, compare); + 'Array, Array': function (x, y) { + // use matrix implementation + return compare(matrix(x), matrix(y)).valueOf(); + }, + + 'Array, Matrix': function (x, y) { + // use matrix implementation + return compare(matrix(x), y); + }, + + 'Matrix, Array': function (x, y) { + // use matrix implementation + return compare(x, matrix(y)); + }, + + 'Matrix, any': function (x, y) { + // result + var c; + // check storage format + switch (x.storage()) { + case 'sparse': + c = algorithm12(x, y, compare, false); + break; + default: + c = algorithm14(x, y, compare, false); + break; + } + return c; + }, + + 'any, Matrix': function (x, y) { + // result + var c; + // check storage format + switch (y.storage()) { + case 'sparse': + c = algorithm12(y, x, compare, true); + break; + default: + c = algorithm14(y, x, compare, true); + break; + } + return c; + }, + + 'Array, any': function (x, y) { + // use matrix implementation + return algorithm14(matrix(x), y, compare, false).valueOf(); + }, + + 'any, Array': function (x, y) { + // use matrix implementation + return algorithm14(matrix(y), x, compare, true).valueOf(); } }); diff --git a/lib/function/relational/equal.js b/lib/function/relational/equal.js index c3155b431..38e0197bc 100644 --- a/lib/function/relational/equal.js +++ b/lib/function/relational/equal.js @@ -1,9 +1,16 @@ 'use strict'; -var nearlyEqual = require('../../util/number').nearlyEqual; - function factory (type, config, load, typed) { - var collection = load(require('../../type/collection')); + + var matrix = load(require('../construction/matrix')); + var equalScalar = load(require('./equalScalar')); + + var algorithm03 = load(require('../../type/matrix/util/algorithm03')); + var algorithm07 = load(require('../../type/matrix/util/algorithm07')); + var algorithm12 = load(require('../../type/matrix/util/algorithm12')); + var algorithm13 = load(require('../../type/matrix/util/algorithm13')); + var algorithm14 = load(require('../../type/matrix/util/algorithm14')); + /** * Test whether two values are equal. * @@ -48,6 +55,7 @@ function factory (type, config, load, typed) { * @return {Boolean | Array | Matrix} Returns true when the compared values are equal, else returns false */ var equal = typed('equal', { + 'any, any': function (x, y) { // strict equality for null and undefined? if (x === null) { return y === null; } @@ -55,45 +63,96 @@ function factory (type, config, load, typed) { if (x === undefined) { return y === undefined; } if (y === undefined) { return x === undefined; } - return _equal(x, y); + return equalScalar(x, y); }, - 'Array | Matrix, any': function (x, y) { - return collection.deepMap2(x, y, _equal); - }, + 'Matrix, Matrix': function (x, y) { + // result + var c; - 'any, Array | Matrix': function (x, y) { - return collection.deepMap2(x, y, _equal); - } - }); - - var _equal = typed('_equal', { - 'boolean, boolean': function (x, y) { - return x === y; - }, - - 'number, number': function (x, y) { - return x === y || nearlyEqual(x, y, config.epsilon); - }, - - 'BigNumber, BigNumber': function (x, y) { - return x.eq(y); - }, - - 'Complex, Complex': function (x, y) { - return (x.re === y.re || nearlyEqual(x.re, y.re, config.epsilon)) && - (x.im === y.im || nearlyEqual(x.im, y.im, config.epsilon)); - }, - - 'Unit, Unit': function (x, y) { - if (!x.equalBase(y)) { - throw new Error('Cannot compare units with different base'); + // process matrix storage + switch (x.storage()) { + case 'sparse': + switch (y.storage()) { + case 'sparse': + // sparse + sparse + c = algorithm07(x, y, equalScalar); + break; + default: + // sparse + dense + c = algorithm03(y, x, equalScalar, true); + break; + } + break; + default: + switch (y.storage()) { + case 'sparse': + // dense + sparse + c = algorithm03(x, y, equalScalar, false); + break; + default: + // dense + dense + c = algorithm13(x, y, equalScalar); + break; + } + break; } - return x.value === y.value || nearlyEqual(x.value, y.value, config.epsilon); + return c; + }, + + 'Array, Array': function (x, y) { + // use matrix implementation + return equal(matrix(x), matrix(y)).valueOf(); }, - 'string, string': function (x, y) { - return x === y; + 'Array, Matrix': function (x, y) { + // use matrix implementation + return equal(matrix(x), y); + }, + + 'Matrix, Array': function (x, y) { + // use matrix implementation + return equal(x, matrix(y)); + }, + + 'Matrix, any': function (x, y) { + // result + var c; + // check storage format + switch (x.storage()) { + case 'sparse': + c = algorithm12(x, y, equalScalar, false); + break; + default: + c = algorithm14(x, y, equalScalar, false); + break; + } + return c; + }, + + 'any, Matrix': function (x, y) { + // result + var c; + // check storage format + switch (y.storage()) { + case 'sparse': + c = algorithm12(y, x, equalScalar, true); + break; + default: + c = algorithm14(y, x, equalScalar, true); + break; + } + return c; + }, + + 'Array, any': function (x, y) { + // use matrix implementation + return algorithm14(matrix(x), y, equalScalar, false).valueOf(); + }, + + 'any, Array': function (x, y) { + // use matrix implementation + return algorithm14(matrix(y), x, equalScalar, true).valueOf(); } }); diff --git a/lib/function/relational/equalScalar.js b/lib/function/relational/equalScalar.js new file mode 100644 index 000000000..3630a1195 --- /dev/null +++ b/lib/function/relational/equalScalar.js @@ -0,0 +1,50 @@ +'use strict'; + +var nearlyEqual = require('../../util/number').nearlyEqual; + +function factory (type, config, load, typed) { + + /** + * Test whether two values are equal. + * + * @param {Number | BigNumber | Boolean | Complex | Unit | null} x First value to compare + * @param {Number | BigNumber | Boolean | Complex | null} y Second value to compare + * @return {Boolean} Returns true when the compared values are equal, else returns false + * @private + */ + var equalScalar = typed('equalScalar', { + + 'boolean, boolean': function (x, y) { + return x === y; + }, + + 'number, number': function (x, y) { + return x === y || nearlyEqual(x, y, config.epsilon); + }, + + 'BigNumber, BigNumber': function (x, y) { + return x.eq(y); + }, + + 'Complex, Complex': function (x, y) { + return (x.re === y.re || nearlyEqual(x.re, y.re, config.epsilon)) && + (x.im === y.im || nearlyEqual(x.im, y.im, config.epsilon)); + }, + + 'Unit, Unit': function (x, y) { + if (!x.equalBase(y)) { + throw new Error('Cannot compare units with different base'); + } + return x.value === y.value || nearlyEqual(x.value, y.value, config.epsilon); + }, + + 'string, string': function (x, y) { + return x === y; + } + }); + + return equalScalar; +} + +exports.name = 'equalScalar'; +exports.factory = factory; diff --git a/lib/function/relational/larger.js b/lib/function/relational/larger.js index 91bcf3dfa..9d776e0b0 100644 --- a/lib/function/relational/larger.js +++ b/lib/function/relational/larger.js @@ -3,7 +3,14 @@ var nearlyEqual = require('../../util/number').nearlyEqual; function factory (type, config, load, typed) { - var collection = load(require('../../type/collection')); + + var matrix = load(require('../construction/matrix')); + + var algorithm03 = load(require('../../type/matrix/util/algorithm03')); + var algorithm07 = load(require('../../type/matrix/util/algorithm07')); + var algorithm12 = load(require('../../type/matrix/util/algorithm12')); + var algorithm13 = load(require('../../type/matrix/util/algorithm13')); + var algorithm14 = load(require('../../type/matrix/util/algorithm14')); /** * Test whether value x is larger than y. @@ -36,6 +43,7 @@ function factory (type, config, load, typed) { * @return {Boolean | Array | Matrix} Returns true when the x is larger than y, else returns false */ var larger = typed('larger', { + 'boolean, boolean': function (x, y) { return x > y; }, @@ -48,7 +56,7 @@ function factory (type, config, load, typed) { return x.gt(y); }, - 'Complex, Complex': function (x, y) { + 'Complex, Complex': function () { throw new TypeError('No ordering relation is defined for complex numbers'); }, @@ -63,12 +71,93 @@ function factory (type, config, load, typed) { return x > y; }, - 'Array | Matrix, any': function (x, y) { - return collection.deepMap2(x, y, larger); + 'Matrix, Matrix': function (x, y) { + // result + var c; + + // process matrix storage + switch (x.storage()) { + case 'sparse': + switch (y.storage()) { + case 'sparse': + // sparse + sparse + c = algorithm07(x, y, larger); + break; + default: + // sparse + dense + c = algorithm03(y, x, larger, true); + break; + } + break; + default: + switch (y.storage()) { + case 'sparse': + // dense + sparse + c = algorithm03(x, y, larger, false); + break; + default: + // dense + dense + c = algorithm13(x, y, larger); + break; + } + break; + } + return c; }, - 'any, Array | Matrix': function (x, y) { - return collection.deepMap2(x, y, larger); + 'Array, Array': function (x, y) { + // use matrix implementation + return larger(matrix(x), matrix(y)).valueOf(); + }, + + 'Array, Matrix': function (x, y) { + // use matrix implementation + return larger(matrix(x), y); + }, + + 'Matrix, Array': function (x, y) { + // use matrix implementation + return larger(x, matrix(y)); + }, + + 'Matrix, any': function (x, y) { + // result + var c; + // check storage format + switch (x.storage()) { + case 'sparse': + c = algorithm12(x, y, larger, false); + break; + default: + c = algorithm14(x, y, larger, false); + break; + } + return c; + }, + + 'any, Matrix': function (x, y) { + // result + var c; + // check storage format + switch (y.storage()) { + case 'sparse': + c = algorithm12(y, x, larger, true); + break; + default: + c = algorithm14(y, x, larger, true); + break; + } + return c; + }, + + 'Array, any': function (x, y) { + // use matrix implementation + return algorithm14(matrix(x), y, larger, false).valueOf(); + }, + + 'any, Array': function (x, y) { + // use matrix implementation + return algorithm14(matrix(y), x, larger, true).valueOf(); } }); diff --git a/lib/function/relational/largerEq.js b/lib/function/relational/largerEq.js index 6e6325b7f..722256e16 100644 --- a/lib/function/relational/largerEq.js +++ b/lib/function/relational/largerEq.js @@ -3,7 +3,14 @@ var nearlyEqual = require('../../util/number').nearlyEqual; function factory (type, config, load, typed) { - var collection = load(require('../../type/collection')); + + var matrix = load(require('../construction/matrix')); + + var algorithm03 = load(require('../../type/matrix/util/algorithm03')); + var algorithm07 = load(require('../../type/matrix/util/algorithm07')); + var algorithm12 = load(require('../../type/matrix/util/algorithm12')); + var algorithm13 = load(require('../../type/matrix/util/algorithm13')); + var algorithm14 = load(require('../../type/matrix/util/algorithm14')); /** * Test whether value x is larger or equal to y. @@ -32,6 +39,7 @@ function factory (type, config, load, typed) { * @return {Boolean | Array | Matrix} Returns true when the x is larger or equal to y, else returns false */ var largerEq = typed('largerEq', { + 'boolean, boolean': function (x, y) { return x >= y; }, @@ -44,7 +52,7 @@ function factory (type, config, load, typed) { return x.gte(y); }, - 'Complex, Complex': function (x, y) { + 'Complex, Complex': function () { throw new TypeError('No ordering relation is defined for complex numbers'); }, @@ -59,12 +67,93 @@ function factory (type, config, load, typed) { return x >= y; }, - 'Array | Matrix, any': function (x, y) { - return collection.deepMap2(x, y, largerEq); + 'Matrix, Matrix': function (x, y) { + // result + var c; + + // process matrix storage + switch (x.storage()) { + case 'sparse': + switch (y.storage()) { + case 'sparse': + // sparse + sparse + c = algorithm07(x, y, largerEq); + break; + default: + // sparse + dense + c = algorithm03(y, x, largerEq, true); + break; + } + break; + default: + switch (y.storage()) { + case 'sparse': + // dense + sparse + c = algorithm03(x, y, largerEq, false); + break; + default: + // dense + dense + c = algorithm13(x, y, largerEq); + break; + } + break; + } + return c; }, - 'any, Array | Matrix': function (x, y) { - return collection.deepMap2(x, y, largerEq); + 'Array, Array': function (x, y) { + // use matrix implementation + return largerEq(matrix(x), matrix(y)).valueOf(); + }, + + 'Array, Matrix': function (x, y) { + // use matrix implementation + return largerEq(matrix(x), y); + }, + + 'Matrix, Array': function (x, y) { + // use matrix implementation + return largerEq(x, matrix(y)); + }, + + 'Matrix, any': function (x, y) { + // result + var c; + // check storage format + switch (x.storage()) { + case 'sparse': + c = algorithm12(x, y, largerEq, false); + break; + default: + c = algorithm14(x, y, largerEq, false); + break; + } + return c; + }, + + 'any, Matrix': function (x, y) { + // result + var c; + // check storage format + switch (y.storage()) { + case 'sparse': + c = algorithm12(y, x, largerEq, true); + break; + default: + c = algorithm14(y, x, largerEq, true); + break; + } + return c; + }, + + 'Array, any': function (x, y) { + // use matrix implementation + return algorithm14(matrix(x), y, largerEq, false).valueOf(); + }, + + 'any, Array': function (x, y) { + // use matrix implementation + return algorithm14(matrix(y), x, largerEq, true).valueOf(); } }); diff --git a/lib/function/relational/smaller.js b/lib/function/relational/smaller.js index 7a03f5240..0fc8dda18 100644 --- a/lib/function/relational/smaller.js +++ b/lib/function/relational/smaller.js @@ -3,13 +3,20 @@ var nearlyEqual = require('../../util/number').nearlyEqual; function factory (type, config, load, typed) { - var collection = load(require('../../type/collection')); + + var matrix = load(require('../construction/matrix')); + + var algorithm03 = load(require('../../type/matrix/util/algorithm03')); + var algorithm07 = load(require('../../type/matrix/util/algorithm07')); + var algorithm12 = load(require('../../type/matrix/util/algorithm12')); + var algorithm13 = load(require('../../type/matrix/util/algorithm13')); + var algorithm14 = load(require('../../type/matrix/util/algorithm14')); /** * Test whether value x is smaller than y. * * The function returns true when x is smaller than y and the relative - * difference between x and y is larger than the configured epsilon. The + * difference between x and y is smaller than the configured epsilon. The * function cannot be used to compare values smaller than approximately 2.22e-16. * * For matrices, the function is evaluated element wise. @@ -29,13 +36,14 @@ function factory (type, config, load, typed) { * * See also: * - * equal, unequal, smallerEq, larger, largerEq, compare + * equal, unequal, smallerEq, smaller, smallerEq, compare * * @param {Number | BigNumber | Boolean | Unit | String | Array | Matrix | null} x First value to compare * @param {Number | BigNumber | Boolean | Unit | String | Array | Matrix | null} y Second value to compare * @return {Boolean | Array | Matrix} Returns true when the x is smaller than y, else returns false */ var smaller = typed('smaller', { + 'boolean, boolean': function (x, y) { return x < y; }, @@ -63,12 +71,93 @@ function factory (type, config, load, typed) { return x < y; }, - 'Array | Matrix, any': function (x, y) { - return collection.deepMap2(x, y, smaller); + 'Matrix, Matrix': function (x, y) { + // result + var c; + + // process matrix storage + switch (x.storage()) { + case 'sparse': + switch (y.storage()) { + case 'sparse': + // sparse + sparse + c = algorithm07(x, y, smaller); + break; + default: + // sparse + dense + c = algorithm03(y, x, smaller, true); + break; + } + break; + default: + switch (y.storage()) { + case 'sparse': + // dense + sparse + c = algorithm03(x, y, smaller, false); + break; + default: + // dense + dense + c = algorithm13(x, y, smaller); + break; + } + break; + } + return c; }, - 'any, Array | Matrix': function (x, y) { - return collection.deepMap2(x, y, smaller); + 'Array, Array': function (x, y) { + // use matrix implementation + return smaller(matrix(x), matrix(y)).valueOf(); + }, + + 'Array, Matrix': function (x, y) { + // use matrix implementation + return smaller(matrix(x), y); + }, + + 'Matrix, Array': function (x, y) { + // use matrix implementation + return smaller(x, matrix(y)); + }, + + 'Matrix, any': function (x, y) { + // result + var c; + // check storage format + switch (x.storage()) { + case 'sparse': + c = algorithm12(x, y, smaller, false); + break; + default: + c = algorithm14(x, y, smaller, false); + break; + } + return c; + }, + + 'any, Matrix': function (x, y) { + // result + var c; + // check storage format + switch (y.storage()) { + case 'sparse': + c = algorithm12(y, x, smaller, true); + break; + default: + c = algorithm14(y, x, smaller, true); + break; + } + return c; + }, + + 'Array, any': function (x, y) { + // use matrix implementation + return algorithm14(matrix(x), y, smaller, false).valueOf(); + }, + + 'any, Array': function (x, y) { + // use matrix implementation + return algorithm14(matrix(y), x, smaller, true).valueOf(); } }); diff --git a/lib/function/relational/smallerEq.js b/lib/function/relational/smallerEq.js index cd6e7e1d8..cb3c4228c 100644 --- a/lib/function/relational/smallerEq.js +++ b/lib/function/relational/smallerEq.js @@ -3,7 +3,14 @@ var nearlyEqual = require('../../util/number').nearlyEqual; function factory (type, config, load, typed) { - var collection = load(require('../../type/collection')); + + var matrix = load(require('../construction/matrix')); + + var algorithm03 = load(require('../../type/matrix/util/algorithm03')); + var algorithm07 = load(require('../../type/matrix/util/algorithm07')); + var algorithm12 = load(require('../../type/matrix/util/algorithm12')); + var algorithm13 = load(require('../../type/matrix/util/algorithm13')); + var algorithm14 = load(require('../../type/matrix/util/algorithm14')); /** * Test whether value x is smaller or equal to y. @@ -31,6 +38,7 @@ function factory (type, config, load, typed) { * @return {Boolean | Array | Matrix} Returns true when the x is smaller than y, else returns false */ var smallerEq = typed('smallerEq', { + 'boolean, boolean': function (x, y) { return x <= y; }, @@ -43,7 +51,7 @@ function factory (type, config, load, typed) { return x.lte(y); }, - 'Complex, Complex': function (x, y) { + 'Complex, Complex': function () { throw new TypeError('No ordering relation is defined for complex numbers'); }, @@ -58,12 +66,93 @@ function factory (type, config, load, typed) { return x <= y; }, - 'Array | Matrix, any': function (x, y) { - return collection.deepMap2(x, y, smallerEq); + 'Matrix, Matrix': function (x, y) { + // result + var c; + + // process matrix storage + switch (x.storage()) { + case 'sparse': + switch (y.storage()) { + case 'sparse': + // sparse + sparse + c = algorithm07(x, y, smallerEq); + break; + default: + // sparse + dense + c = algorithm03(y, x, smallerEq, true); + break; + } + break; + default: + switch (y.storage()) { + case 'sparse': + // dense + sparse + c = algorithm03(x, y, smallerEq, false); + break; + default: + // dense + dense + c = algorithm13(x, y, smallerEq); + break; + } + break; + } + return c; }, - 'any, Array | Matrix': function (x, y) { - return collection.deepMap2(x, y, smallerEq); + 'Array, Array': function (x, y) { + // use matrix implementation + return smallerEq(matrix(x), matrix(y)).valueOf(); + }, + + 'Array, Matrix': function (x, y) { + // use matrix implementation + return smallerEq(matrix(x), y); + }, + + 'Matrix, Array': function (x, y) { + // use matrix implementation + return smallerEq(x, matrix(y)); + }, + + 'Matrix, any': function (x, y) { + // result + var c; + // check storage format + switch (x.storage()) { + case 'sparse': + c = algorithm12(x, y, smallerEq, false); + break; + default: + c = algorithm14(x, y, smallerEq, false); + break; + } + return c; + }, + + 'any, Matrix': function (x, y) { + // result + var c; + // check storage format + switch (y.storage()) { + case 'sparse': + c = algorithm12(y, x, smallerEq, true); + break; + default: + c = algorithm14(y, x, smallerEq, true); + break; + } + return c; + }, + + 'Array, any': function (x, y) { + // use matrix implementation + return algorithm14(matrix(x), y, smallerEq, false).valueOf(); + }, + + 'any, Array': function (x, y) { + // use matrix implementation + return algorithm14(matrix(y), x, smallerEq, true).valueOf(); } }); diff --git a/lib/function/relational/unequal.js b/lib/function/relational/unequal.js index 00b9de4fd..1e30dae0e 100644 --- a/lib/function/relational/unequal.js +++ b/lib/function/relational/unequal.js @@ -3,7 +3,14 @@ var nearlyEqual = require('../../util/number').nearlyEqual; function factory (type, config, load, typed) { - var collection = load(require('../../type/collection')); + + var matrix = load(require('../construction/matrix')); + + var algorithm03 = load(require('../../type/matrix/util/algorithm03')); + var algorithm07 = load(require('../../type/matrix/util/algorithm07')); + var algorithm12 = load(require('../../type/matrix/util/algorithm12')); + var algorithm13 = load(require('../../type/matrix/util/algorithm13')); + var algorithm14 = load(require('../../type/matrix/util/algorithm14')); /** * Test whether two values are unequal. @@ -48,6 +55,7 @@ function factory (type, config, load, typed) { * @return {Boolean | Array | Matrix} Returns true when the compared values are unequal, else returns false */ var unequal = typed('unequal', { + 'any, any': function (x, y) { // strict equality for null and undefined? if (x === null) { return y !== null; } @@ -58,16 +66,98 @@ function factory (type, config, load, typed) { return _unequal(x, y); }, - 'Array | Matrix, any': function (x, y) { - return collection.deepMap2(x, y, _unequal); + 'Matrix, Matrix': function (x, y) { + // result + var c; + + // process matrix storage + switch (x.storage()) { + case 'sparse': + switch (y.storage()) { + case 'sparse': + // sparse + sparse + c = algorithm07(x, y, _unequal); + break; + default: + // sparse + dense + c = algorithm03(y, x, _unequal, true); + break; + } + break; + default: + switch (y.storage()) { + case 'sparse': + // dense + sparse + c = algorithm03(x, y, _unequal, false); + break; + default: + // dense + dense + c = algorithm13(x, y, _unequal); + break; + } + break; + } + return c; }, - 'any, Array | Matrix': function (x, y) { - return collection.deepMap2(x, y, _unequal); + 'Array, Array': function (x, y) { + // use matrix implementation + return unequal(matrix(x), matrix(y)).valueOf(); + }, + + 'Array, Matrix': function (x, y) { + // use matrix implementation + return unequal(matrix(x), y); + }, + + 'Matrix, Array': function (x, y) { + // use matrix implementation + return unequal(x, matrix(y)); + }, + + 'Matrix, any': function (x, y) { + // result + var c; + // check storage format + switch (x.storage()) { + case 'sparse': + c = algorithm12(x, y, _unequal, false); + break; + default: + c = algorithm14(x, y, _unequal, false); + break; + } + return c; + }, + + 'any, Matrix': function (x, y) { + // result + var c; + // check storage format + switch (y.storage()) { + case 'sparse': + c = algorithm12(y, x, _unequal, true); + break; + default: + c = algorithm14(y, x, _unequal, true); + break; + } + return c; + }, + + 'Array, any': function (x, y) { + // use matrix implementation + return algorithm14(matrix(x), y, _unequal, false).valueOf(); + }, + + 'any, Array': function (x, y) { + // use matrix implementation + return algorithm14(matrix(y), x, _unequal, true).valueOf(); } }); var _unequal = typed('_unequal', { + 'boolean, boolean': function (x, y) { return x !== y; }, diff --git a/lib/function/trigonometry/atan2.js b/lib/function/trigonometry/atan2.js index ece644c8c..c84d1333c 100644 --- a/lib/function/trigonometry/atan2.js +++ b/lib/function/trigonometry/atan2.js @@ -3,7 +3,16 @@ var bigAtan2 = require('../../util/bignumber').arctan2; function factory (type, config, load, typed) { - var collection = load(require('../../type/collection')); + + var matrix = load(require('../construction/matrix')); + + var algorithm02 = load(require('../../type/matrix/util/algorithm02')); + var algorithm03 = load(require('../../type/matrix/util/algorithm03')); + var algorithm09 = load(require('../../type/matrix/util/algorithm09')); + var algorithm11 = load(require('../../type/matrix/util/algorithm11')); + var algorithm12 = load(require('../../type/matrix/util/algorithm12')); + var algorithm13 = load(require('../../type/matrix/util/algorithm13')); + var algorithm14 = load(require('../../type/matrix/util/algorithm14')); /** * Calculate the inverse tangent function with two arguments, y/x. @@ -35,6 +44,7 @@ function factory (type, config, load, typed) { * @return {Number | Array | Matrix} Four-quadrant inverse tangent */ var atan2 = typed('atan2', { + 'number, number': Math.atan2, // TODO: implement atan2 for complex numbers @@ -43,12 +53,93 @@ function factory (type, config, load, typed) { return bigAtan2(y, x, type.BigNumber); }, - 'Array | Matrix, any': function (y, x) { - return collection.deepMap2(y, x, atan2); + 'Matrix, Matrix': function (x, y) { + // result + var c; + + // process matrix storage + switch (x.storage()) { + case 'sparse': + switch (y.storage()) { + case 'sparse': + // sparse .* sparse + c = algorithm09(x, y, atan2, false); + break; + default: + // sparse .* dense + c = algorithm02(y, x, atan2, true); + break; + } + break; + default: + switch (y.storage()) { + case 'sparse': + // dense .* sparse + c = algorithm03(x, y, atan2, false); + break; + default: + // dense .* dense + c = algorithm13(x, y, atan2); + break; + } + break; + } + return c; }, - 'any, Array | Matrix': function (y, x) { - return collection.deepMap2(y, x, atan2); + 'Array, Array': function (x, y) { + // use matrix implementation + return atan2(matrix(x), matrix(y)).valueOf(); + }, + + 'Array, Matrix': function (x, y) { + // use matrix implementation + return atan2(matrix(x), y); + }, + + 'Matrix, Array': function (x, y) { + // use matrix implementation + return atan2(x, matrix(y)); + }, + + 'Matrix, number | BigNumber': function (x, y) { + // result + var c; + // check storage format + switch (x.storage()) { + case 'sparse': + c = algorithm11(x, y, atan2, false); + break; + default: + c = algorithm14(x, y, atan2, false); + break; + } + return c; + }, + + 'number | BigNumber, Matrix': function (x, y) { + // result + var c; + // check storage format + switch (y.storage()) { + case 'sparse': + c = algorithm12(y, x, atan2, true); + break; + default: + c = algorithm14(y, x, atan2, true); + break; + } + return c; + }, + + 'Array, number | BigNumber': function (x, y) { + // use matrix implementation + return algorithm14(matrix(x), y, atan2, false).valueOf(); + }, + + 'number | BigNumber, Array': function (x, y) { + // use matrix implementation + return algorithm14(matrix(y), x, atan2, true).valueOf(); } }); diff --git a/lib/function/units/to.js b/lib/function/units/to.js index ab24c771d..2e616e669 100644 --- a/lib/function/units/to.js +++ b/lib/function/units/to.js @@ -1,7 +1,11 @@ 'use strict'; function factory (type, config, load, typed) { - var collection = load(require('../../type/collection')); + + var matrix = load(require('../construction/matrix')); + + var algorithm13 = load(require('../../type/matrix/util/algorithm13')); + var algorithm14 = load(require('../../type/matrix/util/algorithm14')); /** * Change the unit of a value. @@ -28,16 +32,49 @@ function factory (type, config, load, typed) { * @return {Unit | Array | Matrix} value with changed, fixed unit. */ var to = typed('to', { + 'Unit, Unit | string': function (x, unit) { return x.to(unit); }, - 'Array | Matrix, any': function (x, unit) { - return collection.deepMap2(x, unit, to); + 'Matrix, Matrix': function (x, y) { + // SparseMatrix does not support Units + return algorithm13(x, y, to); }, - 'any, Array | Matrix': function (x, unit) { - return collection.deepMap2(x, unit, to); + 'Array, Array': function (x, y) { + // use matrix implementation + return to(matrix(x), matrix(y)).valueOf(); + }, + + 'Array, Matrix': function (x, y) { + // use matrix implementation + return to(matrix(x), y); + }, + + 'Matrix, Array': function (x, y) { + // use matrix implementation + return to(x, matrix(y)); + }, + + 'Matrix, any': function (x, y) { + // SparseMatrix does not support Units + return algorithm14(x, y, to, false); + }, + + 'any, Matrix': function (x, y) { + // SparseMatrix does not support Units + return algorithm14(y, x, to, true); + }, + + 'Array, any': function (x, y) { + // use matrix implementation + return algorithm14(matrix(x), y, to, false).valueOf(); + }, + + 'any, Array': function (x, y) { + // use matrix implementation + return algorithm14(matrix(y), x, to, true).valueOf(); } }); diff --git a/lib/type/Matrix.js b/lib/type/Matrix.js index 92411bc09..6d1d35b1d 100644 --- a/lib/type/Matrix.js +++ b/lib/type/Matrix.js @@ -81,6 +81,19 @@ function factory (type, config, load, typed) { throw new Error('Cannot invoke storage on a Matrix interface'); }; + /** + * Get the datatype of the data stored in the matrix. + * + * Usage: + * var format = matrix.datatype() // retrieve matrix datatype + * + * @return {string} The datatype. + */ + Matrix.prototype.datatype = function () { + // must be implemented by each of the Matrix implementations + throw new Error('Cannot invoke datatype on a Matrix interface'); + }; + /** * Get a subset of the matrix, or replace a subset of the matrix. * diff --git a/lib/type/matrix/DenseMatrix.js b/lib/type/matrix/DenseMatrix.js index 919134372..f2ce24a56 100644 --- a/lib/type/matrix/DenseMatrix.js +++ b/lib/type/matrix/DenseMatrix.js @@ -6,42 +6,53 @@ var DimensionError = require('../../error/DimensionError'); var string = util.string; var array = util.array; var object = util.object; +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) { +function factory (type) { - function DenseMatrix(data) { + var Matrix = type.Matrix; + + function DenseMatrix(data, datatype) { if (!(this instanceof DenseMatrix)) throw new SyntaxError('Constructor must be called with the new operator'); + if (datatype && !isString(datatype)) + throw new Error('Invalid datatype: ' + datatype); - if (data instanceof type.Matrix) { + if (data instanceof Matrix) { // check data is a DenseMatrix if (data.type === 'DenseMatrix') { // clone data & size this._data = object.clone(data._data); this._size = object.clone(data._size); + this._datatype = datatype || data._datatype; } else { // build data from existing matrix this._data = data.toArray(); this._size = data.size(); + this._datatype = datatype || data._datatype; } } else if (data && isArray(data.data) && isArray(data.size)) { // initialize fields from JSON representation this._data = data.data; this._size = data.size; + this._datatype = datatype || data.datatype; } else if (isArray(data)) { // replace nested Matrices with Arrays this._data = preprocess(data); // verify the size of the array, TODO: compute size while processing array this._size = array.size(this._data); + // data type unknown + this._datatype = datatype; } else if (data) { // unsupported type @@ -51,10 +62,11 @@ function factory (type, config, load) { // nothing provided this._data = []; this._size = [0]; + this._datatype = datatype; } } - DenseMatrix.prototype = new type.Matrix(); + DenseMatrix.prototype = new Matrix(); DenseMatrix.prototype.type = 'DenseMatrix'; @@ -69,6 +81,18 @@ function factory (type, config, load) { DenseMatrix.prototype.storage = function () { return 'dense'; }; + + /** + * Get the datatype of the data stored in the matrix. + * + * Usage: + * var format = matrix.datatype() // retrieve matrix datatype + * + * @return {string} The datatype. + */ + DenseMatrix.prototype.datatype = function () { + return this._datatype; + }; /** * Get a subset of the matrix, or replace a subset of the matrix. @@ -417,7 +441,8 @@ function factory (type, config, load) { DenseMatrix.prototype.clone = function () { var m = new DenseMatrix({ data: object.clone(this._data), - size: object.clone(this._size) + size: object.clone(this._size), + datatype: this._datatype }); return m; }; @@ -525,7 +550,8 @@ function factory (type, config, load) { return { mathjs: 'DenseMatrix', data: this._data, - size: this._size + size: this._size, + datatype: this._datatype }; }; diff --git a/lib/type/matrix/Spa.js b/lib/type/matrix/Spa.js index 72ff0bf92..9d9ce9930 100644 --- a/lib/type/matrix/Spa.js +++ b/lib/type/matrix/Spa.js @@ -1,22 +1,20 @@ 'use strict'; -function factory (type, config, load, typed) { +function factory (type, config, load) { var add = load(require('../../function/arithmetic/add')); - var equal = load(require('../../function/relational/equal')); + var equalScalar = load(require('../../function/relational/equalScalar')); /** * An ordered Sparse Accumulator is a representation for a sparse vector that includes a dense array * of the vector elements and an ordered list of non-zero elements. - * - * @param {Integer} length The initial dense vector length. */ - function Spa(length) { + function Spa() { if (!(this instanceof Spa)) throw new SyntaxError('Constructor must be called with the new operator'); // allocate vector, TODO use typed arrays - this._values = new Array(length); + this._values = []; this._heap = new type.FibonacciHeap(); } @@ -77,7 +75,7 @@ function factory (type, config, load, typed) { // check it is in range if (node.key >= from) { // check value is not zero - if (!equal(node.value, 0)) { + if (!equalScalar(node.value, 0)) { // invoke callback callback(node.key, node.value, this); } diff --git a/lib/type/matrix/SparseMatrix.js b/lib/type/matrix/SparseMatrix.js index 85635e831..7411488c5 100644 --- a/lib/type/matrix/SparseMatrix.js +++ b/lib/type/matrix/SparseMatrix.js @@ -9,33 +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 equal = load(require('../../function/relational/equal')); + var equalScalar = load(require('../../function/relational/equalScalar')); - function SparseMatrix(data) { + var Matrix = type.Matrix; + + /** + * 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 (data instanceof type.Matrix) { + 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.values) && isArray(data.index) && isArray(data.ptr) && isArray(data.size)) { + else if (data && isArray(data.index) && isArray(data.ptr) && isArray(data.size)) { // 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 @@ -47,29 +57,32 @@ 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 - matrix._values = object.clone(source._values); + matrix._values = source._values ? object.clone(source._values) : undefined; 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; @@ -95,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 @@ -108,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 @@ -142,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. @@ -156,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: @@ -298,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]; @@ -330,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]; @@ -356,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; } @@ -450,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]; @@ -557,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; }; @@ -584,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 @@ -612,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 @@ -670,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 @@ -711,7 +771,7 @@ function factory (type, config, load) { * @returns {Array} array */ SparseMatrix.prototype.toArray = function () { - return _toArray(this, true); + return _toArray(this._values, this._index, this._ptr, this._size, true); }; /** @@ -719,37 +779,36 @@ function factory (type, config, load) { * @returns {Array} array */ SparseMatrix.prototype.valueOf = function () { - return _toArray(this, false); + return _toArray(this._values, this._index, this._ptr, this._size, false); }; - var _toArray = function (matrix, copy) { + var _toArray = function (values, index, ptr, size, copy) { + // rows and columns + var rows = size[0]; + var columns = size[1]; // result var a = []; - // rows and columns - var rows = matrix._size[0]; - var columns = matrix._size[1]; + // vars + var i, j; + // initialize array + for (i = 0; i < rows; i++) { + a[i] = []; + 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 = matrix._ptr[j]; - var k1 = matrix._ptr[j + 1]; - // row pointer - var p = 0; + var k0 = ptr[j]; + var k1 = ptr[j + 1]; // loop k within [k0, k1[ for (var k = k0; k < k1; k++) { // row index - var i = matrix._index[k]; - // zeros - for (var x = p; x < i; x++) - (a[x] = (a[x] || []))[j] = 0; - // set value - (a[i] = (a[i] || []))[j] = copy ? object.clone(matrix._values[k]) : matrix._values[k]; - // update pointer - p = i + 1; + i = index[k]; + // set value (use one for pattern matrix) + a[i][j] = values ? (copy ? object.clone(values[k]) : values[k]) : 1; } - // zero values - for (var y = p; y < rows; y++) - (a[y] = (a[y] || []))[j] = 0; } return a; }; @@ -766,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] @@ -778,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; @@ -802,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 }; }; @@ -995,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 @@ -1083,36 +1145,42 @@ 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); } } }; diff --git a/lib/type/matrix/util/README.md b/lib/type/matrix/util/README.md new file mode 100644 index 000000000..3ffbe555b --- /dev/null +++ b/lib/type/matrix/util/README.md @@ -0,0 +1,149 @@ +###Algorithms for the implementation of element wise operations between a Dense and Sparse matrices: + +- **Algorithm 1 `x(dense, sparse)`** + * Algorithm should clone `DenseMatrix` and call the `x(d(i,j), s(i,j))` operation for the items in the Dense and Sparse matrices (iterating on the Sparse matrix nonzero items), updating the cloned matrix. + * Output type is a `DenseMatrix` (the cloned matrix) + * `x()` operation invoked NZ times (number of nonzero items in `SparseMatrix`) + + ```` + Cij = x(Dij, Sij); Sij != 0 + Cij = Dij ; otherwise + ```` + +- **Algorithm 2 `x(dense, sparse)`** + * Algorithm should iterate `SparseMatrix` (nonzero items) and call the `x(d(i,j),s(i,j))` operation for the items in the Sparse and Dense matrices (since zero & X == zero) + * Output type is a `SparseMatrix` since the number of nonzero items will be less or equal the number of nonzero elements in the Sparse Matrix. + * `x()` operation invoked NZ times (number of nonzero items in `SparseMatrix`) + + ```` + Cij = x(Dij, Sij); Sij != 0 + Cij = 0 ; otherwise + ```` + +- **Algorithm 3 `x(dense, sparse)`** + * Algorithm should iterate `SparseMatrix` (nonzero and zero items) and call the `x(s(i,j),d(i,j))` operation for the items in the Dense and Sparse matrices + * Output type is a `DenseMatrix` + * `x()` operation invoked M*N times + + ```` + Cij = x(Dij, Sij); Sij != 0 + Cij = x(Dij, 0) ; otherwise + ```` + +- **Algorithm 4 `x(sparse, sparse)`** + * Algorithm should iterate on the nonzero values of matrices A and B and call `x(Aij, Bij)` when both matrices contain value at (i,j) + * Output type is a `SparseMatrix` + * `x()` operation invoked NZ times (number of nonzero items at the same (i,j) for both matrices) + + ```` + Cij = x(Aij, Bij); Aij != 0 && Bij != 0 + Cij = Aij ; Aij != 0 + Cij = Bij ; Bij != 0 + ```` + +###Algorithms for the implementation of element wise operations between a Sparse matrices: + +- **Algorithm 5 `x(sparse, sparse)`** + * Algorithm should iterate on the nonzero values of matrices A and B and call `x(Aij, Bij)` for every nonzero value. + * Output type is a `SparseMatrix` + * `x()` operation invoked NZ times (number of nonzero values in A only + number of nonzero values in B only + number of nonzero values in A and B) + + ```` + Cij = x(Aij, Bij); Aij != 0 || Bij != 0 + Cij = 0 ; otherwise + ```` + +- **Algorithm 6 `x(sparse, sparse)`** + * Algorithm should iterate on the nonzero values of matrices A and B and call `x(Aij, Bij)` when both matrices contain value at (i,j). + * Output type is a `SparseMatrix` + * `x()` operation invoked NZ times (number of nonzero items at the same (i,j) for both matrices) + + ```` + Cij = x(Aij, Bij); Aij != 0 && Bij != 0 + Cij = 0 ; otherwise + ```` + +- **Algorithm 7 `x(sparse, sparse)`** + * Algorithm should iterate on all values of matrices A and B and call `x(Aij, Bij)` + * Output type is a `DenseMatrix` + * `x()` operation invoked MxN times + + ```` + Cij = x(Aij, Bij); + ```` + +- **Algorithm 8 `x(sparse, sparse)`** + * Algorithm should iterate on the nonzero values of matrices A and B and call `x(Aij, Bij)` when both matrices contain value at (i,j). Use the value from Aij when Bij is zero. + * Output type is a `SparseMatrix` + * `x()` operation invoked NZ times (number of nonzero items at the same (i,j) for both matrices) + + ```` + Cij = x(Aij, Bij); Aij != 0 && Bij != 0 + Cij = Aij ; Aij != 0 + Cij = 0 ; otherwise + ```` + +- **Algorithm 9 `x(sparse, sparse)`** + * Algorithm should iterate on the nonzero values of matrices A `x(Aij, Bij)`. + * Output type is a `SparseMatrix` + * `x()` operation invoked NZA times (number of nonzero items in A) + + ```` + Cij = x(Aij, Bij); Aij != 0 + Cij = 0 ; otherwise + ```` + +###Algorithms for the implementation of element wise operations between a Sparse and Scalar Value: + +- **Algorithm 10 `x(sparse, scalar)`** + * Algorithm should iterate on the nonzero values of matrix A and call `x(Aij, N)`. + * Output type is a `DenseMatrix` + * `x()` operation invoked NZ times (number of nonzero items) + + ```` + Cij = x(Aij, N); Aij != 0 + Cij = N ; otherwise + ```` + +- **Algorithm 11 `x(sparse, scalar)`** + * Algorithm should iterate on the nonzero values of matrix A and call `x(Aij, N)`. + * Output type is a `SparseMatrix` + * `x()` operation invoked NZ times (number of nonzero items) + + ```` + Cij = x(Aij, N); Aij != 0** + Cij = 0 ; otherwise** + ```` + +- **Algorithm 12 `x(sparse, scalar)`** + * Algorithm should iterate on the zero and nonzero values of matrix A and call `x(Aij, N)`. + * Output type is a `DenseMatrix` + * `x()` operation invoked MxN times. + + ```` + Cij = x(Aij, N); Aij != 0 + Cij = x(0, N) ; otherwise + ```` + +###Algorithms for the implementation of element wise operations between a Dense and Dense matrices: + +- **Algorithm 13 `x(dense, dense)` + * Algorithm should iterate on the values of matrix A and B for all dimensions and call `x(Aij..z,Bij..z)` + * Output type is a `DenseMatrix` + * `x()` operation invoked Z times, where Z is the number of elements in the matrix last dimension. For two dimensional matrix Z = MxN + + ```` + Cij..z = x(Aij..z, Bij..z)** + ```` + +###Algorithms for the implementation of element wise operations between a Dense Matrix and a Scalar Value: + +- **Algorithm 14 `x(dense, scalar)`** + * Algorithm should iterate on the values of matrix A for all dimensions and call `x(Aij..z, N)` + * Output type is a `DenseMatrix` + * `x()` operation invoked Z times, where Z is the number of elements in the matrix last dimension. + + ```` + Cij..z = x(Aij..z, N)** + ```` + diff --git a/lib/type/matrix/util/algorithm01.js b/lib/type/matrix/util/algorithm01.js new file mode 100644 index 000000000..17fc6fe78 --- /dev/null +++ b/lib/type/matrix/util/algorithm01.js @@ -0,0 +1,114 @@ +'use strict'; + +var DimensionError = require('../../../error/DimensionError'); + +function factory (type) { + + var DenseMatrix = type.DenseMatrix; + + /** + * Iterates over SparseMatrix nonzero items and invokes the callback function f(Dij, Sij). + * Callback function invoked NNZ times (number of nonzero items in SparseMatrix). + * + * + * ┌ f(Dij, Sij) ; S(i,j) !== 0 + * C(i,j) = ┤ + * └ Dij ; otherwise + * + * + * @param {Matrix} denseMatrix The DenseMatrix instance (D) + * @param {Matrix} sparseMatrix The SparseMatrix instance (S) + * @param {function} callback The f(Dij,Sij) operation to invoke, where Dij = DenseMatrix(i,j) and Sij = SparseMatrix(i,j) + * @param {boolean} inverse A true value indicates callback should be invoked f(Sij,Dij) + * + * @return {Matrix} DenseMatrix (C) + * + * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97477571 + */ + var algorithm01 = function (denseMatrix, sparseMatrix, callback, inverse) { + // dense matrix arrays + var adata = denseMatrix._data; + var asize = denseMatrix._size; + var adt = denseMatrix._datatype; + // sparse matrix arrays + var bvalues = sparseMatrix._values; + var bindex = sparseMatrix._index; + var bptr = sparseMatrix._ptr; + var bsize = sparseMatrix._size; + var bdt = sparseMatrix._datatype; + + // validate dimensions + if (asize.length !== bsize.length) + throw new DimensionError(asize.length, bsize.length); + + // check rows & columns + if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) + throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); + + // sparse matrix cannot be a Pattern matrix + if (!bvalues) + throw new Error('Cannot perform operation on Dense Matrix and Pattern Sparse Matrix'); + + // rows & columns + var rows = asize[0]; + var columns = asize[1]; + + // process data types + var dt = adt && bdt && adt === bdt ? adt : undefined; + // callback implementation + var cf = dt && callback.signatures ? callback.signatures[dt + ',' + dt] || callback : callback; + + // vars + var i, j; + + // result (DenseMatrix) + var cdata = []; + // initialize c + for (i = 0; i < rows; i++) + cdata[i] = []; + + // workspace + var x = []; + // marks indicating we have a value in x for a given column + var w = []; + + // loop columns in b + for (j = 0; j < columns; j++) { + // column mark + var mark = j + 1; + // values in column j + for (var k0 = bptr[j], k1 = bptr[j + 1], k = k0; k < k1; k++) { + // row + i = bindex[k]; + // update workspace + x[i] = inverse ? cf(bvalues[k], adata[i][j]) : cf(adata[i][j], bvalues[k]); + // mark i as updated + w[i] = mark; + } + // loop rows + for (i = 0; i < rows; i++) { + // check row is in workspace + if (w[i] === mark) { + // c[i][j] was already calculated + cdata[i][j] = x[i]; + } + else { + // item does not exist in S + cdata[i][j] = adata[i][j]; + } + } + } + + // return dense matrix + return new DenseMatrix({ + data: cdata, + size: [rows, columns], + datatype: dt + }); + }; + + return algorithm01; +} + +exports.name = 'algorithm01'; +exports.factory = factory; diff --git a/lib/type/matrix/util/algorithm02.js b/lib/type/matrix/util/algorithm02.js new file mode 100644 index 000000000..44c4fc63e --- /dev/null +++ b/lib/type/matrix/util/algorithm02.js @@ -0,0 +1,103 @@ +'use strict'; + +var DimensionError = require('../../../error/DimensionError'); + +function factory (type, config, load) { + + var equalScalar = load(require('../../../function/relational/equalScalar')); + + var SparseMatrix = type.SparseMatrix; + + /** + * Iterates over SparseMatrix nonzero items and invokes the callback function f(Dij, Sij). + * Callback function invoked NNZ times (number of nonzero items in SparseMatrix). + * + * + * ┌ f(Dij, Sij) ; S(i,j) !== 0 + * C(i,j) = ┤ + * └ 0 ; otherwise + * + * + * @param {Matrix} denseMatrix The DenseMatrix instance (D) + * @param {Matrix} sparseMatrix The SparseMatrix instance (S) + * @param {function} callback The f(Dij,Sij) operation to invoke, where Dij = DenseMatrix(i,j) and Sij = SparseMatrix(i,j) + * @param {boolean} inverse A true value indicates callback should be invoked f(Sij,Dij) + * + * @return {Matrix} SparseMatrix (C) + * + * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97477571 + */ + var algorithm02 = function (denseMatrix, sparseMatrix, callback, inverse) { + // dense matrix arrays + var adata = denseMatrix._data; + var asize = denseMatrix._size; + var adt = denseMatrix._datatype; + // sparse matrix arrays + var bvalues = sparseMatrix._values; + var bindex = sparseMatrix._index; + var bptr = sparseMatrix._ptr; + var bsize = sparseMatrix._size; + var bdt = sparseMatrix._datatype; + + // validate dimensions + if (asize.length !== bsize.length) + throw new DimensionError(asize.length, bsize.length); + + // check rows & columns + if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) + throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); + + // sparse matrix cannot be a Pattern matrix + if (!bvalues) + throw new Error('Cannot perform operation on Dense Matrix and Pattern Sparse Matrix'); + + // rows & columns + var rows = asize[0]; + var columns = asize[1]; + + // process data types + var dt = adt && bdt && adt === bdt ? adt : undefined; + // callback implementation + var cf = dt && callback.signatures ? callback.signatures[dt + ',' + dt] || callback : callback; + + // result (SparseMatrix) + var cvalues = []; + var cindex = []; + var cptr = []; + + // loop columns in b + for (var j = 0; j < columns; j++) { + // update cptr + cptr[j] = cindex.length; + // values in column j + for (var k0 = bptr[j], k1 = bptr[j + 1], k = k0; k < k1; k++) { + // row + var i = bindex[k]; + // update C(i,j) + var cij = inverse ? cf(bvalues[k], adata[i][j]) : cf(adata[i][j], bvalues[k]); + // check for nonzero + if (!equalScalar(cij, 0)) { + // push i & v + cindex.push(i); + cvalues.push(cij); + } + } + } + // update cptr + cptr[columns] = cindex.length; + + // return sparse matrix + return new SparseMatrix({ + values: cvalues, + index: cindex, + ptr: cptr, + size: [rows, columns], + datatype: dt + }); + }; + + return algorithm02; +} + +exports.name = 'algorithm02'; +exports.factory = factory; diff --git a/lib/type/matrix/util/algorithm03.js b/lib/type/matrix/util/algorithm03.js new file mode 100644 index 000000000..3cb8c02d8 --- /dev/null +++ b/lib/type/matrix/util/algorithm03.js @@ -0,0 +1,117 @@ +'use strict'; + +var DimensionError = require('../../../error/DimensionError'); + +function factory (type) { + + var DenseMatrix = type.DenseMatrix; + + /** + * Iterates over SparseMatrix items and invokes the callback function f(Dij, Sij). + * Callback function invoked M*N times. + * + * + * ┌ f(Dij, Sij) ; S(i,j) !== 0 + * C(i,j) = ┤ + * └ f(Dij, 0) ; otherwise + * + * + * @param {Matrix} denseMatrix The DenseMatrix instance (D) + * @param {Matrix} sparseMatrix The SparseMatrix instance (C) + * @param {function} callback The f(Dij,Sij) operation to invoke, where Dij = DenseMatrix(i,j) and Sij = SparseMatrix(i,j) + * @param {boolean} inverse A true value indicates callback should be invoked f(Sij,Dij) + * + * @return {Matrix} DenseMatrix (C) + * + * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97477571 + */ + var algorithm03 = function (denseMatrix, sparseMatrix, callback, inverse) { + // dense matrix arrays + var adata = denseMatrix._data; + var asize = denseMatrix._size; + var adt = denseMatrix._datatype; + // sparse matrix arrays + var bvalues = sparseMatrix._values; + var bindex = sparseMatrix._index; + var bptr = sparseMatrix._ptr; + var bsize = sparseMatrix._size; + var bdt = sparseMatrix._datatype; + var bzero = sparseMatrix._zero; + + // validate dimensions + if (asize.length !== bsize.length) + throw new DimensionError(asize.length, bsize.length); + + // check rows & columns + if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) + throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); + + // sparse matrix cannot be a Pattern matrix + if (!bvalues) + throw new Error('Cannot perform operation on Dense Matrix and Pattern Sparse Matrix'); + + // rows & columns + var rows = asize[0]; + var columns = asize[1]; + + // process data types (zero value is required!) + var dt = adt && bdt && typeof(bzero) !== 'undefined' && bzero !== null && adt === bdt ? adt : undefined; + // callback implementation + var cf = dt && callback.signatures ? callback.signatures[dt + ',' + dt] || callback : callback; + + // sparse matrix zero value + var zero = dt ? bzero : 0; + + // result (DenseMatrix) + var cdata = []; + + // initialize dense matrix + for (var z = 0; z < rows; z++) { + // initialize row + cdata[z] = []; + } + + // workspace + var x = []; + // marks indicating we have a value in x for a given column + var w = []; + + // loop columns in b + for (var j = 0; j < columns; j++) { + // column mark + var mark = j + 1; + // values in column j + for (var k0 = bptr[j], k1 = bptr[j + 1], k = k0; k < k1; k++) { + // row + var i = bindex[k]; + // update workspace + x[i] = inverse ? cf(bvalues[k], adata[i][j]) : cf(adata[i][j], bvalues[k]); + w[i] = mark; + } + // process workspace + for (var y = 0; y < rows; y++) { + // check we have a calculated value for current row + if (w[y] === mark) { + // use calculated value + cdata[y][j] = x[y]; + } + else { + // calculate value + cdata[y][j] = inverse ? cf(zero, adata[y][j]) : cf(adata[y][j], zero); + } + } + } + + // return dense matrix + return new DenseMatrix({ + data: cdata, + size: [rows, columns], + datatype: dt + }); + }; + + return algorithm03; +} + +exports.name = 'algorithm03'; +exports.factory = factory; diff --git a/lib/type/matrix/util/algorithm04.js b/lib/type/matrix/util/algorithm04.js new file mode 100644 index 000000000..e8848bd80 --- /dev/null +++ b/lib/type/matrix/util/algorithm04.js @@ -0,0 +1,161 @@ +'use strict'; + +var DimensionError = require('../../../error/DimensionError'); + +function factory (type, config, load) { + + var equalScalar = load(require('../../../function/relational/equalScalar')); + + var SparseMatrix = type.SparseMatrix; + + /** + * Iterates over SparseMatrix A and SparseMatrix B nonzero items and invokes the callback function f(Aij, Bij). + * Callback function invoked MAX(NNZA, NNZB) times + * + * + * ┌ f(Aij, Bij) ; A(i,j) !== 0 && B(i,j) !== 0 + * C(i,j) = ┤ A(i,j) ; A(i,j) !== 0 + * └ B(i,j) ; B(i,j) !== 0 + * + * + * @param {Matrix} a The SparseMatrix instance (A) + * @param {Matrix} b The SparseMatrix instance (B) + * @param {function} callback The f(Aij,Bij) operation to invoke + * + * @return {Matrix} SparseMatrix (C) + * + * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97620294 + */ + var algorithm04 = function (a, b, callback) { + // sparse matrix arrays + var avalues = a._values; + var aindex = a._index; + var aptr = a._ptr; + var asize = a._size; + var adt = a._datatype; + var azero = a._zero; + // sparse matrix arrays + var bvalues = b._values; + var bindex = b._index; + var bptr = b._ptr; + var bsize = b._size; + var bdt = b._datatype; + var bzero = b._zero; + + // validate dimensions + if (asize.length !== bsize.length) + throw new DimensionError(asize.length, bsize.length); + + // check rows & columns + if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) + throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); + + // rows & columns + var rows = asize[0]; + var columns = asize[1]; + + // process data types + var dt = adt && bdt && typeof(azero) !== 'undefined' && azero !== null && typeof(bzero) !== 'undefined' && bzero !== null && adt === bdt ? adt : undefined; + // callback implementation + var cf = dt && callback.signatures ? callback.signatures[dt + ',' + dt] || callback : callback; + // equal + var ef = dt ? equalScalar.signatures[dt + ',' + dt] || equalScalar : equalScalar; + + // sparse matrix zero value + var zero = dt ? azero : 0; + + // result arrays + var cvalues = avalues && bvalues ? [] : undefined; + var cindex = []; + var cptr = []; + // matrix + var c = new SparseMatrix({ + values: cvalues, + index: cindex, + ptr: cptr, + size: [rows, columns], + datatype: dt + }); + + // workspace + var x = avalues && bvalues ? [] : undefined; + // marks indicating we have a value in x for a given column + var w = []; + + // vars + var i, j, k, k0, k1; + + // loop columns + for (j = 0; j < columns; j++) { + // update cptr + cptr[j] = cindex.length; + // columns mark + var mark = j + 1; + // loop A(:,j) + for (k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) { + // row + i = aindex[k]; + // update c + cindex.push(i); + // update workspace + w[i] = mark; + // check we need to process values + if (x) + x[i] = avalues[k]; + } + // loop B(:,j) + for (k0 = bptr[j], k1 = bptr[j + 1], k = k0; k < k1; k++) { + // row + i = bindex[k]; + // check row exists in workspace + if (w[i] === mark) { + // check we need to process values + if (x) + x[i] = cf(x[i], bvalues[k]); + } + else { + // update c + cindex.push(i); + // update workspace + w[i] = mark; + // check we need to process values + if (x) + x[i] = cf(x[i], bvalues[k]); + } + } + // check we need to process values (non pattern matrix) + if (x) { + // initialize first index in j + k = cptr[j]; + // loop index in j + while (k < cindex.length) { + // row + i = cindex[k]; + // value @ i + var v = x[i]; + // check for zero value + if (!ef(v, zero)) { + // push value + cvalues.push(v); + // increment pointer + k++; + } + else { + // remove value @ i, do not increment pointer + cindex.splice(k, 1); + } + } + } + } + // update cptr + cptr[columns] = cindex.length; + + // return sparse matrix + return c; + }; + + return algorithm04; +} + +exports.name = 'algorithm04'; +exports.factory = factory; diff --git a/lib/type/matrix/util/algorithm05.js b/lib/type/matrix/util/algorithm05.js new file mode 100644 index 000000000..692b4486f --- /dev/null +++ b/lib/type/matrix/util/algorithm05.js @@ -0,0 +1,168 @@ +'use strict'; + +var DimensionError = require('../../../error/DimensionError'); + +function factory (type, config, load) { + + var equalScalar = load(require('../../../function/relational/equalScalar')); + + var SparseMatrix = type.SparseMatrix; + + /** + * Iterates over SparseMatrix A and SparseMatrix B nonzero items and invokes the callback function f(Aij, Bij). + * Callback function invoked MAX(NNZA, NNZB) times + * + * + * ┌ f(Aij, Bij) ; A(i,j) !== 0 || B(i,j) !== 0 + * C(i,j) = ┤ + * └ 0 ; otherwise + * + * + * @param {Matrix} a The SparseMatrix instance (A) + * @param {Matrix} b The SparseMatrix instance (B) + * @param {function} callback The f(Aij,Bij) operation to invoke + * + * @return {Matrix} SparseMatrix (C) + * + * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97620294 + */ + var algorithm05 = function (a, b, callback) { + // sparse matrix arrays + var avalues = a._values; + var aindex = a._index; + var aptr = a._ptr; + var asize = a._size; + var adt = a._datatype; + var azero = a._zero; + // sparse matrix arrays + var bvalues = b._values; + var bindex = b._index; + var bptr = b._ptr; + var bsize = b._size; + var bdt = b._datatype; + var bzero = b._zero; + + // validate dimensions + if (asize.length !== bsize.length) + throw new DimensionError(asize.length, bsize.length); + + // check rows & columns + if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) + throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); + + // rows & columns + var rows = asize[0]; + var columns = asize[1]; + + // process data types (zero value is required!) + var dt = adt && bdt && typeof(azero) !== 'undefined' && azero !== null && typeof(bzero) !== 'undefined' && bzero !== null && adt === bdt ? adt : undefined; + // callback implementation + var cf = dt && callback.signatures ? callback.signatures[dt + ',' + dt] || callback : callback; + // equal + var ef = dt ? equalScalar.signatures[dt + ',' + dt] || equalScalar : equalScalar; + + // sparse matrix zero value + var zero = dt ? azero : 0; + + // result arrays + var cvalues = avalues && bvalues ? [] : undefined; + var cindex = []; + var cptr = []; + // matrix + var c = new SparseMatrix({ + values: cvalues, + index: cindex, + ptr: cptr, + size: [rows, columns], + datatype: dt, + zero: zero + }); + + // workspaces + var xa = cvalues ? [] : undefined; + var xb = cvalues ? [] : undefined; + // marks indicating we have a value in x for a given column + var wa = []; + var wb = []; + + // vars + var i, j, k, k1; + + // loop columns + for (j = 0; j < columns; j++) { + // update cptr + cptr[j] = cindex.length; + // columns mark + var mark = j + 1; + // loop values A(:,j) + for (k = aptr[j], k1 = aptr[j + 1]; k < k1; k++) { + // row + i = aindex[k]; + // push index + cindex.push(i); + // update workspace + wa[i] = mark; + // check we need to process values + if (xa) + xa[i] = avalues[k]; + } + // loop values B(:,j) + for (k = bptr[j], k1 = bptr[j + 1]; k < k1; k++) { + // row + i = bindex[k]; + // check row existed in A + if (wa[i] !== mark) { + // push index + cindex.push(i); + } + // update workspace + wb[i] = mark; + // check we need to process values + if (xb) + xb[i] = bvalues[k]; + } + // check we need to process values (non pattern matrix) + if (cvalues) { + // initialize first index in j + k = cptr[j]; + // loop index in j + while (k < cindex.length) { + // row + i = cindex[k]; + // marks + var wai = wa[i]; + var wbi = wb[i]; + // check Aij or Bij are nonzero + if (wai === mark || wbi === mark) { + // matrix values @ i,j + var va = wai === mark ? xa[i] : zero; + var vb = wbi === mark ? xb[i] : zero; + // Cij + var vc = cf(va, vb); + // check for zero + if (!ef(vc, zero)) { + // push value + cvalues.push(vc); + // increment pointer + k++; + } + else { + // remove value @ i, do not increment pointer + cindex.splice(k, 1); + } + } + } + } + } + // update cptr + cptr[columns] = cindex.length; + + // return sparse matrix + return c; + }; + + return algorithm05; +} + +exports.name = 'algorithm05'; +exports.factory = factory; diff --git a/lib/type/matrix/util/algorithm06.js b/lib/type/matrix/util/algorithm06.js new file mode 100644 index 000000000..c98552de4 --- /dev/null +++ b/lib/type/matrix/util/algorithm06.js @@ -0,0 +1,155 @@ +'use strict'; + +var DimensionError = require('../../../error/DimensionError'); + +function factory (type, config, load) { + + var equalScalar = load(require('../../../function/relational/equalScalar')); + var scatter = load(require('./scatter')); + + var SparseMatrix = type.SparseMatrix; + + /** + * Iterates over SparseMatrix A and SparseMatrix B nonzero items and invokes the callback function f(Aij, Bij). + * Callback function invoked (Anz U Bnz) times, where Anz and Bnz are the nonzero elements in both matrices. + * + * + * ┌ f(Aij, Bij) ; A(i,j) !== 0 && B(i,j) !== 0 + * C(i,j) = ┤ + * └ 0 ; otherwise + * + * + * @param {Matrix} a The SparseMatrix instance (A) + * @param {Matrix} b The SparseMatrix instance (B) + * @param {function} callback The f(Aij,Bij) operation to invoke + * + * @return {Matrix} SparseMatrix (C) + * + * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97620294 + */ + var algorithm06 = function (a, b, callback) { + // sparse matrix arrays + var avalues = a._values; + var asize = a._size; + var adt = a._datatype; + var azero = a._zero; + // sparse matrix arrays + var bvalues = b._values; + var bsize = b._size; + var bdt = b._datatype; + var bzero = b._zero; + + // validate dimensions + if (asize.length !== bsize.length) + throw new DimensionError(asize.length, bsize.length); + + // check rows & columns + if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) + throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); + + // rows & columns + var rows = asize[0]; + var columns = asize[1]; + + // process data types (zero value is required!) + var dt = adt && bdt && typeof(azero) !== 'undefined' && azero !== null && typeof(bzero) !== 'undefined' && bzero !== null && adt === bdt ? adt : undefined; + // callback implementation + var cf = dt && callback.signatures ? callback.signatures[dt + ',' + dt] || callback : callback; + // equal + var ef = dt ? equalScalar.signatures[dt + ',' + dt] || equalScalar : equalScalar; + + // sparse matrix zero value + var zero = dt ? azero : 0; + + // result arrays + var cvalues = avalues && bvalues ? [] : undefined; + var cindex = []; + var cptr = []; + // matrix + var c = new SparseMatrix({ + values: cvalues, + index: cindex, + ptr: cptr, + size: [rows, columns], + datatype: dt, + zero: zero + }); + + // workspaces + var x = cvalues ? [] : undefined; + // marks indicating we have a value in x for a given column + var w = []; + // marks indicating value in a given row has been updated + var u = []; + + // loop columns + for (var j = 0; j < columns; j++) { + // update cptr + cptr[j] = cindex.length; + // columns mark + var mark = j + 1; + // scatter the values of A(:,j) into workspace + scatter(a, j, w, x, u, mark, c, cf); + // scatter the values of B(:,j) into workspace + scatter(b, j, w, x, u, mark, c, cf); + // check we need to process values (non pattern matrix) + if (x) { + // initialize first index in j + var k = cptr[j]; + // loop index in j + while (k < cindex.length) { + // row + var i = cindex[k]; + // check function was invoked on current row (Aij !=0 && Bij != 0) + if (u[i] === mark) { + // value @ i + var v = x[i]; + // check for zero value + if (!ef(v, zero)) { + // push value + cvalues.push(v); + // increment pointer + k++; + } + else { + // remove value @ i, do not increment pointer + cindex.splice(k, 1); + } + } + else { + // remove value @ i, do not increment pointer + cindex.splice(k, 1); + } + } + } + else { + // initialize first index in j + var p = cptr[j]; + // loop index in j + while (p < cindex.length) { + // row + var r = cindex[p]; + // check function was invoked on current row (Aij !=0 && Bij != 0) + if (u[r] !== mark) { + // remove value @ i, do not increment pointer + cindex.splice(p, 1); + } + else { + // increment pointer + p++; + } + } + } + } + // update cptr + cptr[columns] = cindex.length; + + // return sparse matrix + return c; + }; + + return algorithm06; +} + +exports.name = 'algorithm06'; +exports.factory = factory; diff --git a/lib/type/matrix/util/algorithm07.js b/lib/type/matrix/util/algorithm07.js new file mode 100644 index 000000000..ef14fb5b6 --- /dev/null +++ b/lib/type/matrix/util/algorithm07.js @@ -0,0 +1,117 @@ +'use strict'; + +var DimensionError = require('../../../error/DimensionError'); + +function factory (type) { + + var DenseMatrix = type.DenseMatrix; + + /** + * Iterates over SparseMatrix A and SparseMatrix B items (zero and nonzero) and invokes the callback function f(Aij, Bij). + * Callback function invoked MxN times. + * + * C(i,j) = f(Aij, Bij) + * + * @param {Matrix} a The SparseMatrix instance (A) + * @param {Matrix} b The SparseMatrix instance (B) + * @param {function} callback The f(Aij,Bij) operation to invoke + * + * @return {Matrix} DenseMatrix (C) + * + * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97620294 + */ + var algorithm07 = function (a, b, callback) { + // sparse matrix arrays + var asize = a._size; + var adt = a._datatype; + var azero = a._zero; + // sparse matrix arrays + var bsize = b._size; + var bdt = b._datatype; + var bzero = b._zero; + + // validate dimensions + if (asize.length !== bsize.length) + throw new DimensionError(asize.length, bsize.length); + + // check rows & columns + if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) + throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); + + // rows & columns + var rows = asize[0]; + var columns = asize[1]; + + // process data types (zero value is required!) + var dt = adt && bdt && typeof(azero) !== 'undefined' && azero !== null && typeof(bzero) !== 'undefined' && bzero !== null && adt === bdt ? adt : undefined; + // callback implementation + var cf = dt && callback.signatures ? callback.signatures[dt + ',' + dt] || callback : callback; + + // sparse matrix zero value + var zero = dt ? azero : 0; + + // vars + var i, j; + + // result arrays + var cdata = []; + // initialize c + for (i = 0; i < rows; i++) + cdata[i] = []; + + // matrix + var c = new DenseMatrix({ + data: cdata, + size: [rows, columns], + datatype: dt + }); + + // workspaces + var xa = []; + var xb = []; + // marks indicating we have a value in x for a given column + var wa = []; + var wb = []; + + // loop columns + for (j = 0; j < columns; j++) { + // columns mark + var mark = j + 1; + // scatter the values of A(:,j) into workspace + _scatter(a, j, wa, xa, mark); + // scatter the values of B(:,j) into workspace + _scatter(b, j, wb, xb, mark); + // loop rows + for (i = 0; i < rows; i++) { + // matrix values @ i,j + var va = wa[i] === mark ? xa[i] : zero; + var vb = wb[i] === mark ? xb[i] : zero; + // invoke callback + cdata[i][j] = cf(va, vb); + } + } + + // return sparse matrix + return c; + }; + + var _scatter = function (m, j, w, x, mark) { + // a arrays + var values = m._values; + var index = m._index; + var ptr = m._ptr; + // loop values in column j + for (var k = ptr[j], k1 = ptr[j + 1]; k < k1; k++) { + // row + var i = index[k]; + // update workspace + w[i] = mark; + x[i] = values[k]; + } + }; + + return algorithm07; +} + +exports.name = 'algorithm07'; +exports.factory = factory; diff --git a/lib/type/matrix/util/algorithm08.js b/lib/type/matrix/util/algorithm08.js new file mode 100644 index 000000000..2e1ae06f6 --- /dev/null +++ b/lib/type/matrix/util/algorithm08.js @@ -0,0 +1,151 @@ +'use strict'; + +var DimensionError = require('../../../error/DimensionError'); + +function factory (type, config, load) { + + var equalScalar = load(require('../../../function/relational/equalScalar')); + + var SparseMatrix = type.SparseMatrix; + + /** + * Iterates over SparseMatrix A and SparseMatrix B nonzero items and invokes the callback function f(Aij, Bij). + * Callback function invoked MAX(NNZA, NNZB) times + * + * + * ┌ f(Aij, Bij) ; A(i,j) !== 0 && B(i,j) !== 0 + * C(i,j) = ┤ A(i,j) ; A(i,j) !== 0 + * └ 0 ; otherwise + * + * + * @param {Matrix} a The SparseMatrix instance (A) + * @param {Matrix} b The SparseMatrix instance (B) + * @param {function} callback The f(Aij,Bij) operation to invoke + * + * @return {Matrix} SparseMatrix (C) + * + * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97620294 + */ + var algorithm08 = function (a, b, callback) { + // sparse matrix arrays + var avalues = a._values; + var aindex = a._index; + var aptr = a._ptr; + var asize = a._size; + var adt = a._datatype; + var azero = a._zero; + // sparse matrix arrays + var bvalues = b._values; + var bindex = b._index; + var bptr = b._ptr; + var bsize = b._size; + var bdt = b._datatype; + var bzero = b._zero; + + // validate dimensions + if (asize.length !== bsize.length) + throw new DimensionError(asize.length, bsize.length); + + // check rows & columns + if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) + throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); + + // sparse matrix cannot be a Pattern matrix + if (!avalues || !bvalues) + throw new Error('Cannot perform operation on Pattern Sparse Matrices'); + + // rows & columns + var rows = asize[0]; + var columns = asize[1]; + + // process data types (zero value is required!) + var dt = adt && bdt && typeof(azero) !== 'undefined' && azero !== null && typeof(bzero) !== 'undefined' && bzero !== null && adt === bdt ? adt : undefined; + // callback implementation + var cf = dt && callback.signatures ? callback.signatures[dt + ',' + dt] || callback : callback; + // equal + var ef = dt ? equalScalar.signatures[dt + ',' + dt] || equalScalar : equalScalar; + + // sparse matrix zero value + var zero = dt ? azero : 0; + + // result arrays + var cvalues = []; + var cindex = []; + var cptr = []; + // matrix + var c = new SparseMatrix({ + values: cvalues, + index: cindex, + ptr: cptr, + size: [rows, columns], + datatype: dt + }); + + // workspace + var x = []; + // marks indicating we have a value in x for a given column + var w = []; + + // vars + var k, k0, k1, i; + + // loop columns + for (var j = 0; j < columns; j++) { + // update cptr + cptr[j] = cindex.length; + // columns mark + var mark = j + 1; + // loop values in a + for (k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) { + // row + i = aindex[k]; + // mark workspace + w[i] = mark; + // set value + x[i] = avalues[k]; + // add index + cindex.push(i); + } + // loop values in b + for (k0 = bptr[j], k1 = bptr[j + 1], k = k0; k < k1; k++) { + // row + i = bindex[k]; + // check value exists in workspace + if (w[i] === mark) { + // evaluate callback + x[i] = cf(x[i], bvalues[k]); + } + } + // initialize first index in j + k = cptr[j]; + // loop index in j + while (k < cindex.length) { + // row + i = cindex[k]; + // value @ i + var v = x[i]; + // check for zero value + if (!ef(v, zero)) { + // push value + cvalues.push(v); + // increment pointer + k++; + } + else { + // remove value @ i, do not increment pointer + cindex.splice(k, 1); + } + } + } + // update cptr + cptr[columns] = cindex.length; + + // return sparse matrix + return c; + }; + + return algorithm08; +} + +exports.name = 'algorithm08'; +exports.factory = factory; diff --git a/lib/type/matrix/util/algorithm09.js b/lib/type/matrix/util/algorithm09.js new file mode 100644 index 000000000..422c2d2ff --- /dev/null +++ b/lib/type/matrix/util/algorithm09.js @@ -0,0 +1,141 @@ +'use strict'; + +var DimensionError = require('../../../error/DimensionError'); + +function factory (type, config, load) { + + var equalScalar = load(require('../../../function/relational/equalScalar')); + + var SparseMatrix = type.SparseMatrix; + + /** + * Iterates over SparseMatrix A and invokes the callback function f(Aij, Bij). + * Callback function invoked NZA times, number of nonzero elements in A. + * + * + * ┌ f(Aij, Bij) ; A(i,j) !== 0 + * C(i,j) = ┤ + * └ 0 ; otherwise + * + * + * @param {Matrix} a The SparseMatrix instance (A) + * @param {Matrix} b The SparseMatrix instance (B) + * @param {function} callback The f(Aij,Bij) operation to invoke + * + * @return {Matrix} SparseMatrix (C) + * + * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97620294 + */ + var algorithm09 = function (a, b, callback) { + // sparse matrix arrays + var avalues = a._values; + var aindex = a._index; + var aptr = a._ptr; + var asize = a._size; + var adt = a._datatype; + var azero = a._zero; + // sparse matrix arrays + var bvalues = b._values; + var bindex = b._index; + var bptr = b._ptr; + var bsize = b._size; + var bdt = b._datatype; + var bzero = b._zero; + + // validate dimensions + if (asize.length !== bsize.length) + throw new DimensionError(asize.length, bsize.length); + + // check rows & columns + if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) + throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); + + // rows & columns + var rows = asize[0]; + var columns = asize[1]; + + // process data types (zero value is required!) + var dt = adt && bdt && typeof(azero) !== 'undefined' && azero !== null && typeof(bzero) !== 'undefined' && bzero !== null && adt === bdt ? adt : undefined; + // callback implementation + var cf = dt && callback.signatures ? callback.signatures[dt + ',' + dt] || callback : callback; + // equal + var ef = dt ? equalScalar.signatures[dt + ',' + dt] || equalScalar : equalScalar; + + // sparse matrix zero value + var zero = dt ? azero : 0; + + // result arrays + var cvalues = avalues && bvalues ? [] : undefined; + var cindex = []; + var cptr = []; + // matrix + var c = new SparseMatrix({ + values: cvalues, + index: cindex, + ptr: cptr, + size: [rows, columns], + datatype: dt, + zero: zero + }); + + // workspaces + var x = cvalues ? [] : undefined; + // marks indicating we have a value in x for a given column + var w = []; + + // vars + var i, j, k, k0, k1; + + // loop columns + for (j = 0; j < columns; j++) { + // update cptr + cptr[j] = cindex.length; + // column mark + var mark = j + 1; + // check we need to process values + if (x) { + // loop B(:,j) + for (k0 = bptr[j], k1 = bptr[j + 1], k = k0; k < k1; k++) { + // row + i = bindex[k]; + // update workspace + w[i] = mark; + x[i] = bvalues[k]; + } + } + // loop A(:,j) + for (k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) { + // row + i = aindex[k]; + // check we need to process values + if (x) { + // b value @ i,j + var vb = w[i] === mark ? x[i] : zero; + // invoke f + var vc = cf(avalues[k], vb); + // check zero value + if (!ef(vc, zero)) { + // push index + cindex.push(i); + // push value + cvalues.push(vc); + } + } + else { + // push index + cindex.push(i); + } + } + } + // update cptr + cptr[columns] = cindex.length; + + // return sparse matrix + return c; + }; + + return algorithm09; +} + +exports.name = 'algorithm09'; +exports.factory = factory; diff --git a/lib/type/matrix/util/algorithm10.js b/lib/type/matrix/util/algorithm10.js new file mode 100644 index 000000000..e124d02cd --- /dev/null +++ b/lib/type/matrix/util/algorithm10.js @@ -0,0 +1,93 @@ +'use strict'; + +function factory (type) { + + var DenseMatrix = type.DenseMatrix; + + /** + * Iterates over SparseMatrix S nonzero items and invokes the callback function f(Sij, b). + * Callback function invoked NZ times (number of nonzero items in S). + * + * + * ┌ f(Sij, b) ; S(i,j) !== 0 + * C(i,j) = ┤ + * └ b ; otherwise + * + * + * @param {Matrix} s The SparseMatrix instance (S) + * @param {Scalar} b The Scalar value + * @param {function} callback The f(Aij,b) operation to invoke + * @param {boolean} inverse A true value indicates callback should be invoked f(b,Sij) + * + * @return {Matrix} DenseMatrix (C) + * + * https://github.com/josdejong/mathjs/pull/346#issuecomment-97626813 + */ + var algorithm10 = function (s, b, callback, inverse) { + // sparse matrix arrays + var avalues = s._values; + var aindex = s._index; + var aptr = s._ptr; + var asize = s._size; + + // sparse matrix cannot be a Pattern matrix + if (!avalues) + throw new Error('Cannot perform operation on Pattern Sparse Matrix and Scalar value'); + + // rows & columns + var rows = asize[0]; + var columns = asize[1]; + + // result arrays + var cdata = []; + // matrix + var c = new DenseMatrix({ + data: cdata, + size: [rows, columns] + }); + + // workspaces + var x = []; + // marks indicating we have a value in x for a given column + var w = []; + + // loop columns + for (var j = 0; j < columns; j++) { + // columns mark + var mark = j + 1; + // values in j + for (var k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) { + // row + var r = aindex[k]; + // update workspace + x[r] = avalues[k]; + w[r] = mark; + } + // loop rows + for (var i = 0; i < rows; i++) { + // initialize C on first column + if (j === 0) { + // create row array + cdata[i] = []; + } + // check sparse matrix has a value @ i,j + if (w[i] === mark) { + // invoke callback, update C + cdata[i][j] = inverse ? callback(b, x[i]) : callback(x[i], b); + } + else { + // dense matrix value @ i, j + cdata[i][j] = b; + } + } + } + + // return sparse matrix + return c; + }; + + return algorithm10; +} + +exports.name = 'algorithm10'; +exports.factory = factory; diff --git a/lib/type/matrix/util/algorithm11.js b/lib/type/matrix/util/algorithm11.js new file mode 100644 index 000000000..eaf75d7a2 --- /dev/null +++ b/lib/type/matrix/util/algorithm11.js @@ -0,0 +1,84 @@ +'use strict'; + +function factory (type, config, load) { + + var equalScalar = load(require('../../../function/relational/equalScalar')); + + var SparseMatrix = type.SparseMatrix; + + /** + * Iterates over SparseMatrix S nonzero items and invokes the callback function f(Sij, b). + * Callback function invoked NZ times (number of nonzero items in S). + * + * + * ┌ f(Sij, b) ; S(i,j) !== 0 + * C(i,j) = ┤ + * └ 0 ; otherwise + * + * + * @param {Matrix} s The SparseMatrix instance (S) + * @param {Scalar} b The Scalar value + * @param {function} callback The f(Aij,b) operation to invoke + * @param {boolean} inverse A true value indicates callback should be invoked f(b,Sij) + * + * @return {Matrix} SparseMatrix (C) + * + * https://github.com/josdejong/mathjs/pull/346#issuecomment-97626813 + */ + var algorithm11 = function (s, b, callback, inverse) { + // sparse matrix arrays + var avalues = s._values; + var aindex = s._index; + var aptr = s._ptr; + var asize = s._size; + + // sparse matrix cannot be a Pattern matrix + if (!avalues) + throw new Error('Cannot perform operation on Pattern Sparse Matrix and Scalar value'); + + // rows & columns + var rows = asize[0]; + var columns = asize[1]; + + // result arrays + var cvalues = []; + var cindex = []; + var cptr = []; + // matrix + var c = new SparseMatrix({ + values: cvalues, + index: cindex, + ptr: cptr, + size: [rows, columns] + }); + + // loop columns + for (var j = 0; j < columns; j++) { + // initialize ptr + cptr[j] = cindex.length; + // values in j + for (var k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) { + // row + var i = aindex[k]; + // invoke callback + var v = inverse ? callback(b, avalues[k]) : callback(avalues[k], b); + // check value is zero + if (!equalScalar(v, 0)) { + // push index & value + cindex.push(i); + cvalues.push(v); + } + } + } + // update ptr + cptr[columns] = cindex.length; + + // return sparse matrix + return c; + }; + + return algorithm11; +} + +exports.name = 'algorithm11'; +exports.factory = factory; diff --git a/lib/type/matrix/util/algorithm12.js b/lib/type/matrix/util/algorithm12.js new file mode 100644 index 000000000..6cd883935 --- /dev/null +++ b/lib/type/matrix/util/algorithm12.js @@ -0,0 +1,93 @@ +'use strict'; + +function factory (type) { + + var DenseMatrix = type.DenseMatrix; + + /** + * Iterates over SparseMatrix S nonzero items and invokes the callback function f(Sij, b). + * Callback function invoked MxN times. + * + * + * ┌ f(Sij, b) ; S(i,j) !== 0 + * C(i,j) = ┤ + * └ f(0, b) ; otherwise + * + * + * @param {Matrix} s The SparseMatrix instance (S) + * @param {Scalar} b The Scalar value + * @param {function} callback The f(Aij,b) operation to invoke + * @param {boolean} inverse A true value indicates callback should be invoked f(b,Sij) + * + * @return {Matrix} DenseMatrix (C) + * + * https://github.com/josdejong/mathjs/pull/346#issuecomment-97626813 + */ + var algorithm12 = function (s, b, callback, inverse) { + // sparse matrix arrays + var avalues = s._values; + var aindex = s._index; + var aptr = s._ptr; + var asize = s._size; + + // sparse matrix cannot be a Pattern matrix + if (!avalues) + throw new Error('Cannot perform operation on Pattern Sparse Matrix and Scalar value'); + + // rows & columns + var rows = asize[0]; + var columns = asize[1]; + + // result arrays + var cdata = []; + // matrix + var c = new DenseMatrix({ + data: cdata, + size: [rows, columns] + }); + + // workspaces + var x = []; + // marks indicating we have a value in x for a given column + var w = []; + + // loop columns + for (var j = 0; j < columns; j++) { + // columns mark + var mark = j + 1; + // values in j + for (var k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) { + // row + var r = aindex[k]; + // update workspace + x[r] = avalues[k]; + w[r] = mark; + } + // loop rows + for (var i = 0; i < rows; i++) { + // initialize C on first column + if (j === 0) { + // create row array + cdata[i] = []; + } + // check sparse matrix has a value @ i,j + if (w[i] === mark) { + // invoke callback, update C + cdata[i][j] = inverse ? callback(b, x[i]) : callback(x[i], b); + } + else { + // dense matrix value @ i, j + cdata[i][j] = inverse ? callback(b, 0) : callback(0, b); + } + } + } + + // return sparse matrix + return c; + }; + + return algorithm12; +} + +exports.name = 'algorithm12'; +exports.factory = factory; diff --git a/lib/type/matrix/util/algorithm13.js b/lib/type/matrix/util/algorithm13.js new file mode 100644 index 000000000..6f14ae378 --- /dev/null +++ b/lib/type/matrix/util/algorithm13.js @@ -0,0 +1,90 @@ +'use strict'; + +var DimensionError = require('../../../error/DimensionError'); + +function factory (type) { + + var DenseMatrix = type.DenseMatrix; + + /** + * Iterates over DenseMatrix items and invokes the callback function f(Aij..z, Bij..z). + * Callback function invoked MxN times. + * + * C(i,j,...z) = f(Aij..z, Bij..z) + * + * @param {Matrix} a The DenseMatrix instance (A) + * @param {Matrix} b The DenseMatrix instance (B) + * @param {function} callback The f(Aij..z,Bij..z) operation to invoke + * + * @return {Matrix} DenseMatrix (C) + * + * https://github.com/josdejong/mathjs/pull/346#issuecomment-97658658 + */ + var algorithm13 = function (a, b, callback) { + // a arrays + var adata = a._data; + var asize = a._size; + var adt = a._datatype; + // b arrays + var bdata = b._data; + var bsize = b._size; + var bdt = b._datatype; + // c arrays + var csize = []; + + // validate dimensions + if (asize.length !== bsize.length) + throw new DimensionError(asize.length, bsize.length); + + // validate each one of the dimension sizes + for (var s = 0; s < asize.length; s++) { + // must match + if (asize[s] !== bsize[s]) + throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); + // update dimension in c + csize[s] = asize[s]; + } + + // process data types + var dt = adt && bdt && adt === bdt ? adt : undefined; + // callback implementation + var cf = dt && callback.signatures ? callback.signatures[dt + ',' + dt] || callback : callback; + + // populate cdata, iterate through dimensions + var cdata = csize.length > 0 ? _iterate(cf, 0, csize, csize[0], adata, bdata) : []; + + // c matrix + return new DenseMatrix({ + data: cdata, + size: csize, + datatype: dt + }); + }; + + // recursive function + var _iterate = function (f, level, s, n, av, bv) { + // initialize array for this level + var cv = []; + // check we reach the last level + if (level === s.length - 1) { + // loop arrays in last level + for (var i = 0; i < n; i++) { + // invoke callback and store value + cv[i] = f(av[i], bv[i]); + } + } + else { + // iterate current level + for (var j = 0; j < n; j++) { + // iterate next level + cv[j] = _iterate(f, level + 1, s, s[level + 1], av[j], bv[j]); + } + } + return cv; + }; + + return algorithm13; +} + +exports.name = 'algorithm13'; +exports.factory = factory; diff --git a/lib/type/matrix/util/algorithm14.js b/lib/type/matrix/util/algorithm14.js new file mode 100644 index 000000000..ce6922c37 --- /dev/null +++ b/lib/type/matrix/util/algorithm14.js @@ -0,0 +1,68 @@ +'use strict'; + +var util = require('../../../util/index'); + +var object = util.object; + +function factory (type) { + + var DenseMatrix = type.DenseMatrix; + + /** + * Iterates over DenseMatrix items and invokes the callback function f(Aij..z, b). + * Callback function invoked MxN times. + * + * C(i,j,...z) = f(Aij..z, b) + * + * @param {Matrix} a The DenseMatrix instance (A) + * @param {Scalar} b The Scalar value + * @param {function} callback The f(Aij..z,b) operation to invoke + * @param {boolean} inverse A true value indicates callback should be invoked f(b,Aij..z) + * + * @return {Matrix} DenseMatrix (C) + * + * https://github.com/josdejong/mathjs/pull/346#issuecomment-97659042 + */ + var algorithm14 = function (a, b, callback, inverse) { + // a arrays + var adata = a._data; + var asize = a._size; + + // populate cdata, iterate through dimensions + var cdata = asize.length > 0 ? _iterate(callback, 0, asize, asize[0], adata, b, inverse) : []; + + // c matrix + return new DenseMatrix({ + data: cdata, + size: object.clone(asize), + datatype: undefined + }); + }; + + // recursive function + var _iterate = function (f, level, s, n, av, bv, inverse) { + // initialize array for this level + var cv = []; + // check we reach the last level + if (level === s.length - 1) { + // loop arrays in last level + for (var i = 0; i < n; i++) { + // invoke callback and store value + cv[i] = inverse ? f(bv, av[i]) : f(av[i], bv); + } + } + else { + // iterate current level + for (var j = 0; j < n; j++) { + // iterate next level + cv[j] = _iterate(f, level + 1, s, s[level + 1], av[j], bv, inverse); + } + } + return cv; + }; + + return algorithm14; +} + +exports.name = 'algorithm14'; +exports.factory = factory; diff --git a/lib/type/matrix/util/scatter.js b/lib/type/matrix/util/scatter.js new file mode 100644 index 000000000..7dad5e9b8 --- /dev/null +++ b/lib/type/matrix/util/scatter.js @@ -0,0 +1,72 @@ +'use strict'; + +function factory () { + + var scatter = function (a, j, w, x, u, mark, c, f, inverse, update, value) { + // a arrays + var avalues = a._values; + var aindex = a._index; + var aptr = a._ptr; + // c arrays + var cindex = c._index; + + // vars + var k, k0, k1, i; + + // check we need to process values (pattern matrix) + if (x) { + // values in j + for (k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) { + // row + i = aindex[k]; + // check value exists in current j + if (w[i] !== mark) { + // i is new entry in j + w[i] = mark; + // add i to pattern of C + cindex.push(i); + // x(i) = A, check we need to call function this time + if (update) { + // copy value to workspace calling callback function + x[i] = inverse ? f(avalues[k], value) : f(value, avalues[k]); + // function was called on current row + u[i] = mark; + } + else { + // copy value to workspace + x[i] = avalues[k]; + } + } + else { + // i exists in C already + x[i] = inverse ? f(avalues[k], x[i]) : f(x[i], avalues[k]); + // function was called on current row + u[i] = mark; + } + } + } + else { + // values in j + for (k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) { + // row + i = aindex[k]; + // check value exists in current j + if (w[i] !== mark) { + // i is new entry in j + w[i] = mark; + // add i to pattern of C + cindex.push(i); + } + else { + // indicate function was called on current row + u[i] = mark; + } + } + } + }; + + return scatter; +} + +exports.name = 'scatter'; +exports.factory = factory; diff --git a/test/expression/node/BlockNode.test.js b/test/expression/node/BlockNode.test.js index 6f0de63dd..ec1cc42ae 100644 --- a/test/expression/node/BlockNode.test.js +++ b/test/expression/node/BlockNode.test.js @@ -258,7 +258,7 @@ describe('BlockNode', function() { {node: new SymbolNode('foo'), visible:true} ]); - assert.equal(n.toTex(), '5\nfoo:=3;\n foo'); + assert.equal(n.toTex(), '5\\;\\;\nfoo:=3;\\;\\;\n foo'); }); it ('should LaTeX a BlockNode with custom toTex', function () { diff --git a/test/function/algebra/decomposition/lup.test.js b/test/function/algebra/decomposition/lup.test.js index 996b63a55..4830ab2e0 100644 --- a/test/function/algebra/decomposition/lup.test.js +++ b/test/function/algebra/decomposition/lup.test.js @@ -17,7 +17,7 @@ describe('lup', function () { // P assert.deepEqual(r.P.valueOf(), [[1, 0], [0, 1]]); // verify - approx.deepEqual(math.multiply(r.P, m), math.multiply(r.L, r.U)); + approx.deepEqual(math.multiply(r.P, m).valueOf(), math.multiply(r.L, r.U).valueOf()); }); it('should decompose matrix, n x n, no permutations, sparse', function () { @@ -32,7 +32,7 @@ describe('lup', function () { // P assert.deepEqual(r.P.valueOf(), [[1, 0], [0, 1]]); // verify - approx.deepEqual(math.multiply(r.P, m), math.multiply(r.L, r.U)); + approx.deepEqual(math.multiply(r.P, m).valueOf(), math.multiply(r.L, r.U).valueOf()); }); it('should decompose matrix, n x n, no permutations, dense format', function () { @@ -47,7 +47,7 @@ describe('lup', function () { // P assert.deepEqual(r.P.valueOf(), [[1, 0], [0, 1]]); // verify - approx.deepEqual(math.multiply(r.P, m), math.multiply(r.L, r.U)); + approx.deepEqual(math.multiply(r.P, m).valueOf(), math.multiply(r.L, r.U).valueOf()); }); it('should decompose matrix, m x n, m < n, no permutations, dense format', function () { @@ -87,7 +87,7 @@ describe('lup', function () { ] )); // verify - approx.deepEqual(math.multiply(r.P, m), math.multiply(r.L, r.U)); + approx.deepEqual(math.multiply(r.P, m).valueOf(), math.multiply(r.L, r.U).valueOf()); }); it('should decompose matrix, m x n, m > n, no permutations, dense format', function () { @@ -130,7 +130,7 @@ describe('lup', function () { ] )); // verify - approx.deepEqual(math.multiply(r.P, m), math.multiply(r.L, r.U)); + approx.deepEqual(math.multiply(r.P, m).valueOf(), math.multiply(r.L, r.U).valueOf()); }); it('should decompose matrix, n x n, dense format', function () { @@ -172,7 +172,7 @@ describe('lup', function () { [1, 0, 0, 0] ]); // verify - approx.deepEqual(math.multiply(r.P, m), math.multiply(r.L, r.U)); + approx.deepEqual(math.multiply(r.P, m).valueOf(), math.multiply(r.L, r.U).valueOf()); }); it('should decompose matrix, 3 x 3, zero pivote value, dense format', function () { @@ -209,7 +209,7 @@ describe('lup', function () { [1, 0, 0] ]); // verify - approx.deepEqual(math.multiply(r.P, m), math.multiply(r.L, r.U)); + approx.deepEqual(math.multiply(r.P, m).valueOf(), math.multiply(r.L, r.U).valueOf()); }); it('should decompose matrix, 3 x 2, complex numbers, dense format', function () { @@ -245,7 +245,7 @@ describe('lup', function () { [0, 0, 1] ]); // verify - approx.deepEqual(math.multiply(r.P, m), math.multiply(r.L, r.U)); + approx.deepEqual(math.multiply(r.P, m).valueOf(), math.multiply(r.L, r.U).valueOf()); }); it('should decompose matrix, m x n, m < n, no permutations, sparse', function () { @@ -279,7 +279,7 @@ describe('lup', function () { [0, 1] ]); // verify - approx.deepEqual(math.multiply(r.P, m), math.multiply(r.L, r.U)); + approx.deepEqual(math.multiply(r.P, m).valueOf(), math.multiply(r.L, r.U).valueOf()); }); it('should decompose matrix, m x n, m > n, no permutations, sparse', function () { @@ -316,7 +316,7 @@ describe('lup', function () { [0, 0, 1] ]); // verify - approx.deepEqual(math.multiply(r.P, m), math.multiply(r.L, r.U)); + approx.deepEqual(math.multiply(r.P, m).valueOf(), math.multiply(r.L, r.U).valueOf()); }); it('should decompose matrix, n x n, sparse', function () { @@ -358,7 +358,7 @@ describe('lup', function () { [1, 0, 0, 0] ]); // verify - approx.deepEqual(math.multiply(r.P, m), math.multiply(r.L, r.U)); + approx.deepEqual(math.multiply(r.P, m).valueOf(), math.multiply(r.L, r.U).valueOf()); }); it('should decompose matrix, 3 x 3, zero pivote value, sparse', function () { @@ -396,7 +396,7 @@ describe('lup', function () { [1, 0, 0] ]); // verify - approx.deepEqual(math.multiply(r.P, m), math.multiply(r.L, r.U)); + approx.deepEqual(math.multiply(r.P, m).valueOf(), math.multiply(r.L, r.U).valueOf()); }); it('should decompose matrix, 3 x 2, complex numbers, sparse', function () { @@ -432,6 +432,6 @@ describe('lup', function () { [0, 0, 1] ]); // verify - approx.deepEqual(math.multiply(r.P, m), math.multiply(r.L, r.U)); + approx.deepEqual(math.multiply(r.P, m).valueOf(), math.multiply(r.L, r.U).valueOf()); }); }); diff --git a/test/function/arithmetic/add.test.js b/test/function/arithmetic/add.test.js index a63954c3a..26c64efc4 100644 --- a/test/function/arithmetic/add.test.js +++ b/test/function/arithmetic/add.test.js @@ -1,7 +1,6 @@ // test add var assert = require('assert'); var approx = require('../../../tools/approx'); -var error = require('../../../lib/error/index'); var math = require('../../../index'); var BigNumber = require('decimal.js'); var add = math.add; @@ -46,8 +45,8 @@ describe('add', function() { assert.deepEqual(add(new BigNumber(0.1), 0.2), new BigNumber(0.3)); assert.deepEqual(add(0.1, new BigNumber(0.2)), new math.type.BigNumber(0.3)); - assert.throws(function () {add(1/3, new BigNumber(1))}, /Cannot implicitly convert a number with >15 significant digits to BigNumber/); - assert.throws(function () {add(new BigNumber(1), 1/3)}, /Cannot implicitly convert a number with >15 significant digits to BigNumber/); + assert.throws(function () {add(1/3, new BigNumber(1));}, /Cannot implicitly convert a number with >15 significant digits to BigNumber/); + assert.throws(function () {add(new BigNumber(1), 1/3);}, /Cannot implicitly convert a number with >15 significant digits to BigNumber/); }); it('should add mixed booleans and BigNumbers', function() { @@ -88,9 +87,9 @@ describe('add', function() { }); it('should throw an error in case of a unit and non-unit argument', function() { - assert.throws(function () {add(math.unit('5cm'), 2)}, /TypeError/); - assert.throws(function () {add(math.unit('5cm'), new Date())}, /TypeError/); - assert.throws(function () {add(new Date(), math.unit('5cm'))}, /TypeError/); + assert.throws(function () {add(math.unit('5cm'), 2);}, /TypeError/); + assert.throws(function () {add(math.unit('5cm'), new Date());}, /TypeError/); + assert.throws(function () {add(new Date(), math.unit('5cm'));}, /TypeError/); }); it('should concatenate two strings', function() { @@ -98,51 +97,220 @@ describe('add', function() { assert.equal(add('str', 123), 'str123'); assert.equal(add(123, 'str'), '123str'); }); + + describe('Array', function () { + + it('should concatenate strings and array element wise', function() { + assert.deepEqual(add('A', ['B', 'C']), ['AB', 'AC']); + assert.deepEqual(add(['B', 'C'], 'A'), ['BA', 'CA']); + }); + + it('should add arrays correctly', function() { + var a2 = [[1,2],[3,4]]; + var a3 = [[5,6],[7,8]]; + var a4 = add(a2, a3); + assert.deepEqual(a4, [[6,8],[10,12]]); + }); + + it('should add 3 dimension arrays correctly', function() { + var a2 = [[[1,1],[2,2]],[[3,3],[4,4]]]; + var a3 = [[[5,5],[6,6]],[[7,7],[8,8]]]; + var a4 = add(a2, a3); + assert.deepEqual(a4, [[[6,6],[8,8]],[[10,10],[12,12]]]); + }); + + it('should add a scalar and an array correctly', function() { + assert.deepEqual(add(2, [3,4]), [5,6]); + assert.deepEqual(add([3,4], 2), [5,6]); + }); - it('should concatenate strings and matrices element wise', function() { - assert.deepEqual(add('A', ['B', 'C']), ['AB', 'AC']); - assert.deepEqual(add(['B', 'C'], 'A'), ['BA', 'CA']); + it('should add array and dense matrix correctly', function() { + var a = [1,2,3]; + var b = math.matrix([3,2,1]); + var c = add(a, b); - assert.deepEqual(add('A', math.matrix(['B', 'C'])), math.matrix(['AB', 'AC'])); - assert.deepEqual(add(math.matrix(['B', 'C']), 'A'), math.matrix(['BA', 'CA'])); + assert.ok(c instanceof math.type.Matrix); + assert.deepEqual(c, math.matrix([4,4,4])); + }); + + it('should add array and sparse matrix correctly', function() { + var a = [[1,2,3],[4,5,6]]; + var b = math.sparse([[6, 5, 4],[ 3, 2, 1]]); + var c = add(a, b); + + assert.ok(c instanceof math.type.Matrix); + assert.deepEqual(c, math.matrix([[7,7,7],[7,7,7]])); + }); }); - it('should add matrices correctly', function() { - var a2 = math.matrix([[1,2],[3,4]]); - var a3 = math.matrix([[5,6],[7,8]]); - var a4 = add(a2, a3); - assert.ok(a4 instanceof math.type.Matrix); - assert.deepEqual(a4.size(), [2,2]); - assert.deepEqual(a4.valueOf(), [[6,8],[10,12]]); + describe('DenseMatrix', function () { + + it('should concatenate strings and matrices element wise', function() { + assert.deepEqual(add('A', math.matrix(['B', 'C'])), math.matrix(['AB', 'AC'])); + assert.deepEqual(add(math.matrix(['B', 'C']), 'A'), math.matrix(['BA', 'CA'])); + }); + + it('should add matrices correctly', function() { + var a2 = math.matrix([[1,2],[3,4]]); + var a3 = math.matrix([[5,6],[7,8]]); + var a4 = add(a2, a3); + assert.ok(a4 instanceof math.type.Matrix); + assert.deepEqual(a4.size(), [2,2]); + assert.deepEqual(a4.valueOf(), [[6,8],[10,12]]); + }); + + it('should add 3 dimension natrices correctly', function() { + var a2 = math.matrix([[[1,1],[2,2]],[[3,3],[4,4]]]); + var a3 = math.matrix([[[5,5],[6,6]],[[7,7],[8,8]]]); + var a4 = add(a2, a3); + assert.deepEqual(a4, math.matrix([[[6,6],[8,8]],[[10,10],[12,12]]])); + }); + + it('should add a scalar and a matrix correctly', function() { + assert.deepEqual(add(2, math.matrix([3,4])), math.matrix([5,6])); + assert.deepEqual(add(math.matrix([3,4]), 2), math.matrix([5,6])); + }); - var a5 = math.add(a2, 2); - assert.ok(a5 instanceof math.type.Matrix); - assert.deepEqual(a5.size(), [2,2]); - assert.deepEqual(a5.valueOf(), [[3,4],[5,6]]); + it('should add matrix and array correctly', function() { + var a = math.matrix([1,2,3]); + var b = [3,2,1]; + var c = add(a, b); + + assert.ok(c instanceof math.type.Matrix); + assert.deepEqual(c, math.matrix([4,4,4])); + }); + + it('should add dense and sparse matrices correctly', function() { + var a = math.matrix([[1,2,3],[1,0,0]]); + var b = math.sparse([[3,2,1],[0,0,1]]); + var c = add(a, b); + + assert.ok(c instanceof math.type.Matrix); + assert.deepEqual(c, math.matrix([[4,4,4],[1,0,1]])); + }); }); + + describe('SparseMatrix', function () { - it('should add a scalar and a matrix correctly', function() { - assert.deepEqual(add(2, math.matrix([3,4])), math.matrix([5,6])); - assert.deepEqual(add(math.matrix([3,4]), 2), math.matrix([5,6])); + it('should add matrices correctly', function() { + var a2 = math.matrix([[1,2],[3,4]], 'sparse'); + var a3 = math.matrix([[5,-2],[7,-4]], 'sparse'); + var a4 = add(a2, a3); + assert.ok(a4 instanceof math.type.Matrix); + assert.deepEqual(a4, math.sparse([[6,0],[10,0]])); + }); + + it('should add a scalar and a matrix correctly', function() { + assert.deepEqual(add(2, math.matrix([[3,4],[5,6]], 'sparse')), math.matrix([[5,6],[7,8]], 'dense')); + assert.deepEqual(add(math.matrix([[3,4],[5,6]], 'sparse'), 2), math.matrix([[5,6],[7,8]], 'dense')); + }); + + it('should add matrix and array correctly', function() { + var a = math.matrix([[1,2,3],[1,0,0]], 'sparse'); + var b = [[3,2,1],[0,0,1]]; + var c = add(a, b); + + assert.ok(c instanceof math.type.Matrix); + assert.deepEqual(c, math.matrix([[4,4,4],[1,0,1]])); + }); + + it('should add sparse and dense matrices correctly', function() { + var a = math.sparse([[1,2,3],[1,0,0]]); + var b = math.matrix([[3,2,1],[0,0,1]]); + var c = add(a, b); + + assert.ok(c instanceof math.type.Matrix); + assert.deepEqual(c, math.matrix([[4,4,4],[1,0,1]])); + }); + + it('should add two pattern matrices correctly', function() { + + var a = new math.type.SparseMatrix({ + values: undefined, + index: [0, 1, 2, 0], + ptr: [0, 2, 3, 4], + size: [3, 3] + }); + + var b = new math.type.SparseMatrix({ + values: undefined, + index: [0, 1, 2, 1], + ptr: [0, 3, 3, 4], + size: [3, 3] + }); + + var c = add(a, b); + + assert.deepEqual( + c, + new math.type.SparseMatrix({ + values: undefined, + index: [0, 1, 2, 2, 0, 1], + ptr: [0, 3, 4, 6], + size: [3, 3] + })); + }); + + it('should add pattern and value matrices correctly', function() { + + var a = new math.type.SparseMatrix({ + values: undefined, + index: [0, 1, 2, 0], + ptr: [0, 2, 3, 4], + size: [3, 3] + }); + + var b = new math.type.SparseMatrix({ + values: [1, 2, 3, 4], + index: [0, 1, 2, 1], + ptr: [0, 3, 3, 4], + size: [3, 3] + }); + + var c = add(a, b); + + assert.deepEqual( + c, + new math.type.SparseMatrix({ + values: undefined, + index: [0, 1, 2, 2, 0, 1], + ptr: [0, 3, 4, 6], + size: [3, 3] + })); + }); + + it('should add value and pattern matrices correctly', function() { + + var a = new math.type.SparseMatrix({ + values: [1, 2, 3, 4], + index: [0, 1, 2, 0], + ptr: [0, 2, 3, 4], + size: [3, 3] + }); + + var b = new math.type.SparseMatrix({ + values: undefined, + index: [0, 1, 2, 1], + ptr: [0, 3, 3, 4], + size: [3, 3] + }); + + var c = add(a, b); + + assert.deepEqual( + c, + new math.type.SparseMatrix({ + values: undefined, + index: [0, 1, 2, 2, 0, 1], + ptr: [0, 3, 4, 6], + size: [3, 3] + })); + }); }); - - it('should add a scalar and an array correctly', function() { - assert.deepEqual(add(2, [3,4]), [5,6]); - assert.deepEqual(add([3,4], 2), [5,6]); - }); - - it('should add a matrix and an array correctly', function() { - var a = [1,2,3]; - var b = math.matrix([3,2,1]); - var c = add(a, b); - - assert.ok(c instanceof math.type.Matrix); - assert.deepEqual(c, math.matrix([4,4,4])); - }); - + it('should throw an error in case of invalid number of arguments', function() { - assert.throws(function () {add(1)}, /TypeError: Too few arguments/); - assert.throws(function () {add(1, 2, 3)}, /TypeError: Too many arguments/); + assert.throws(function () {add(1);}, /TypeError: Too few arguments/); + assert.throws(function () {add(1, 2, 3);}, /TypeError: Too many arguments/); }); it('should LaTeX add', function () { diff --git a/test/function/arithmetic/dotDivide.test.js b/test/function/arithmetic/dotDivide.test.js index da0c18b8e..ff23a9cca 100644 --- a/test/function/arithmetic/dotDivide.test.js +++ b/test/function/arithmetic/dotDivide.test.js @@ -1,12 +1,12 @@ // test dotDivide (element-wise divide) var assert = require('assert'), math = require('../../../index'), - error = require('../../../lib/error/index'), approx = require('../../../tools/approx'), dotDivide = math.dotDivide, complex = math.complex; describe('dotDivide', function() { + it('should divide two numbers', function() { assert.equal(dotDivide(4, 2), 2); assert.equal(dotDivide(-4, 2), -2); @@ -53,43 +53,119 @@ describe('dotDivide', function() { }); it('should throw an error if dividing a number by a unit', function() { - assert.throws(function () {dotDivide(10, math.unit('5 m')).toString()}); + assert.throws(function () {dotDivide(10, math.unit('5 m')).toString();}); }); - it('should divide all the elements of a matrix by one number', function() { - assert.deepEqual(dotDivide([2,4,6], 2), [1,2,3]); - var a = math.matrix([[1,2],[3,4]]); - assert.deepEqual(dotDivide(a, 2), math.matrix([[0.5,1],[1.5,2]])); - assert.deepEqual(dotDivide(a.valueOf(), 2), [[0.5,1],[1.5,2]]); - assert.deepEqual(dotDivide([], 2), []); - assert.deepEqual(dotDivide([], 2), []); - }); + describe('Array', function () { - it('should divide 1 over a matrix element-wise', function() { - approx.deepEqual(math.format(dotDivide(1, [ - [ 1, 4, 7], - [ 3, 0, 5], - [-1, 9, 11] - ])), math.format([ - [ 1, 0.25, 1/7], - [ 1/3, Infinity, 0.2], - [-1, 1/9, 1/11] - ])); - }); + it('should divide all the elements of a array by one number', function() { + assert.deepEqual(dotDivide([2,4,6], 2), [1,2,3]); + var a = [[1,2],[3,4]]; + assert.deepEqual(dotDivide(a, 2), [[0.5,1],[1.5,2]]); + assert.deepEqual(dotDivide([], 2), []); + }); - it('should perform matrix element-wise matrix division', function() { - a = math.matrix([[1,2],[3,4]]); - b = math.matrix([[5,6],[7,8]]); - assert.deepEqual(dotDivide(a, b), math.matrix([[1/5, 2/6], [3/7,4/8]])); + it('should divide 1 over a array element-wise', function() { + approx.deepEqual(dotDivide(1, [[1, 4, 7], [ 3, 0, 5], [-1, 9, 11]]), [[1, 0.25, 1/7],[1/3, Infinity, 0.2], [-1, 1/9, 1/11]]); + }); + + it('should perform (array ./ array) element-wise matrix division', function() { + var a = [[1,2],[3,4]]; + var b = [[5,6],[7,8]]; + assert.deepEqual(dotDivide(a, b), [[1/5, 2/6], [3/7,4/8]]); + }); + + it('should perform (array ./ dense matrix) element-wise matrix division', function() { + var a = [[1,2],[3,4]]; + var b = math.matrix([[5,6],[7,8]]); + assert.deepEqual(dotDivide(a, b), math.matrix([[1/5, 2/6], [3/7,4/8]])); + }); + + it('should perform (array ./ sparse matrix) element-wise matrix division', function() { + var a = [[1,2],[3,4]]; + var b = math.sparse([[5,0],[7,8]]); + assert.deepEqual(dotDivide(a, b), math.matrix([[1/5, Infinity], [3/7,4/8]])); + }); + + it('should throw an error when dividing element-wise with differing size', function() { + assert.throws(function () {dotDivide([[1,2],[3,4]], [[1]]);}); + }); }); + + describe('DenseMatrix', function () { + + it('should divide all the elements of a dense matrix by one number', function() { + assert.deepEqual(dotDivide(math.matrix([2,4,6]), 2), math.matrix([1,2,3])); + var a = math.matrix([[1,2],[3,4]]); + assert.deepEqual(dotDivide(a, 2), math.matrix([[0.5,1],[1.5,2]])); + assert.deepEqual(dotDivide(math.matrix([]), 2), math.matrix([])); + }); - it('should throw an error when dividing element-wise by a matrix with differing size', function() { - assert.throws(function () {dotDivide(a, [[1]])}); + it('should divide 1 over a dense matrix element-wise', function() { + approx.deepEqual(dotDivide(1, math.matrix([[1, 4, 7], [ 3, 0, 5], [-1, 9, 11]])), math.matrix([[1, 0.25, 1/7],[1/3, Infinity, 0.2], [-1, 1/9, 1/11]])); + }); + + it('should perform (dense matrix ./ array) element-wise matrix division', function() { + var a = math.matrix([[1,2],[3,4]]); + var b = [[5,6],[7,8]]; + assert.deepEqual(dotDivide(a, b), math.matrix([[1/5, 2/6], [3/7,4/8]])); + }); + + it('should perform (dense matrix ./ dense matrix) element-wise matrix division', function() { + var a = math.matrix([[1,2],[3,4]]); + var b = math.matrix([[5,6],[7,8]]); + assert.deepEqual(dotDivide(a, b), math.matrix([[1/5, 2/6], [3/7,4/8]])); + }); + + it('should perform (dense matrix ./ sparse matrix) element-wise matrix division', function() { + var a = math.matrix([[1,2],[3,4]]); + var b = math.sparse([[5,0],[7,8]]); + assert.deepEqual(dotDivide(a, b), math.matrix([[1/5, Infinity], [3/7,4/8]])); + }); + + it('should throw an error when dividing element-wise with differing size', function() { + assert.throws(function () {dotDivide(math.matrix([[1,2],[3,4]]), math.matrix([[1]]));}); + }); + }); + + describe('SparseMatrix', function () { + + it('should divide all the elements of a sparse matrix by one number', function() { + assert.deepEqual(dotDivide(math.sparse([[2,0,6],[8,10,12]]), 2), math.sparse([[1,0,3],[4,5,6]])); + var a = math.sparse([[1,2],[3,4]]); + assert.deepEqual(dotDivide(a, 2), math.sparse([[0.5,1],[1.5,2]])); + assert.deepEqual(dotDivide(math.sparse(), 2), math.sparse()); + }); + + it('should divide 1 over a sparse matrix element-wise', function() { + approx.deepEqual(dotDivide(1, math.sparse([[1, 4, 7], [ 3, 0, 5], [-1, 9, 11]])), math.matrix([[1, 0.25, 1/7],[1/3, Infinity, 0.2], [-1, 1/9, 1/11]])); + }); + + it('should perform (sparse matrix ./ array) element-wise matrix division', function() { + var a = math.sparse([[1,2],[3,4]]); + var b = [[5,6],[7,8]]; + assert.deepEqual(dotDivide(a, b), math.sparse([[1/5, 2/6], [3/7,4/8]])); + }); + + it('should perform (sparse matrix ./ dense matrix) element-wise matrix division', function() { + var a = math.sparse([[1,2],[3,4]]); + var b = math.matrix([[5,6],[7,8]]); + assert.deepEqual(dotDivide(a, b), math.sparse([[1/5, 2/6], [3/7,4/8]])); + }); + + it('should perform (sparse matrix ./ sparse matrix) element-wise matrix division', function() { + var a = math.sparse([[1,2],[0,4]]); + var b = math.sparse([[5,0],[7,8]]); + assert.deepEqual(dotDivide(a, b), math.matrix([[1/5, Infinity], [0,4/8]])); + }); + + it('should throw an error when dividing element-wise with differing size', function() { + assert.throws(function () {dotDivide(math.sparse([[1,2],[3,4]]), math.sparse([[1]]));}); + }); }); it('should LaTeX dotDivide', function () { var expression = math.parse('dotDivide([1,2],[3,4])'); assert.equal(expression.toTex(), '\\left(\\begin{bmatrix}1\\\\2\\\\\\end{bmatrix}.:\\begin{bmatrix}3\\\\4\\\\\\end{bmatrix}\\right)'); }); - }); diff --git a/test/function/arithmetic/dotMultiply.test.js b/test/function/arithmetic/dotMultiply.test.js index 3fcd5f054..adaa853dc 100644 --- a/test/function/arithmetic/dotMultiply.test.js +++ b/test/function/arithmetic/dotMultiply.test.js @@ -6,6 +6,7 @@ var assert = require('assert'), dotMultiply = math.dotMultiply, divide = math.divide, matrix = math.matrix, + sparse = math.sparse, complex = math.complex, range = math.range, i = math.i, @@ -65,29 +66,115 @@ describe('dotMultiply', function() { assert.throws(function () {dotMultiply("hello", 2)}); }); - var a = matrix([[1,2],[3,4]]); - var b = matrix([[5,6],[7,8]]); - var c = matrix([[5],[6]]); - var d = matrix([[5,6]]); - - it('should multiply a all elements in a matrix by a number', function() { - // matrix, array, range - approx.deepEqual(dotMultiply(a, 3), matrix([[3,6],[9,12]])); - approx.deepEqual(dotMultiply(3, a), matrix([[3,6],[9,12]])); + describe('Array', function () { + + var a = [[1,0],[3,4]]; + var b = [[5,6],[0,8]]; + var c = [[5],[6]]; + var d = [[5,6]]; + + it('should multiply a all elements in a array by a number', function() { + // matrix, array, range + approx.deepEqual(dotMultiply(a, 3), [[3,0],[9,12]]); + approx.deepEqual(dotMultiply(3, a), [[3,0],[9,12]]); + approx.deepEqual(dotMultiply([1,2,3,4], 2), [2, 4, 6, 8]); + approx.deepEqual(dotMultiply(2, [1,2,3,4]), [2, 4, 6, 8]); + }); + + it('should perform element-wise (array .* array) multiplication', function() { + approx.deepEqual(dotMultiply(a, b), [[5,0],[0,32]]); + approx.deepEqual(dotMultiply([[1,2],[3,4]], [[5,6],[7,8]]), [[5,12],[21,32]]); + }); + + it('should perform element-wise (array .* dense matrix) multiplication', function() { + approx.deepEqual(dotMultiply([[1,2],[3,4]], matrix([[5,6],[7,8]])), matrix([[5,12],[21,32]])); + }); + + it('should perform element-wise (array .* sparse matrix) multiplication', function() { + approx.deepEqual(dotMultiply([[1,2],[3,4]], sparse([[5,6],[7,8]])), sparse([[5,12],[21,32]])); + }); + + it('should throw an error if arrays are of different sizes', function() { + assert.throws(function () {dotMultiply(a, c)}); + assert.throws(function () {dotMultiply(d, a)}); + assert.throws(function () {dotMultiply(d, b)}); + assert.throws(function () {dotMultiply(d, c)}); + assert.throws(function () {dotMultiply(c, b)}); + }); }); + + describe('DenseMatrix', function () { - it('should perform element-wise matrix multiplication', function() { - approx.deepEqual(dotMultiply(a, b), matrix([[5,12],[21,32]])); - approx.deepEqual(dotMultiply([[1,2],[3,4]], [[5,6],[7,8]]), [[5,12],[21,32]]); - approx.deepEqual(dotMultiply([1,2,3,4], 2), [2, 4, 6, 8]); + var a = matrix([[1,0],[3,4]]); + var b = matrix([[5,6],[0,8]]); + var c = matrix([[5],[6]]); + var d = matrix([[5,6]]); + + it('should multiply a all elements in a dense matrix by a number', function() { + // matrix, array, range + approx.deepEqual(dotMultiply(a, 3), matrix([[3,0],[9,12]])); + approx.deepEqual(dotMultiply(3, a), matrix([[3,0],[9,12]])); + approx.deepEqual(dotMultiply(matrix([1,2,3,4]), 2), matrix([2, 4, 6, 8])); + approx.deepEqual(dotMultiply(2, matrix([1,2,3,4])), matrix([2, 4, 6, 8])); + }); + + it('should perform element-wise (dense matrix .* array) multiplication', function() { + approx.deepEqual(dotMultiply(a, [[5,6],[0,8]]), matrix([[5,0],[0,32]])); + approx.deepEqual(dotMultiply(matrix([[1,2],[3,4]]), [[5,6],[7,8]]), matrix([[5,12],[21,32]])); + }); + + it('should perform element-wise (dense matrix .* dense matrix) multiplication', function() { + approx.deepEqual(dotMultiply(matrix([[1,2],[3,4]]), matrix([[5,6],[7,8]])), matrix([[5,12],[21,32]])); + }); + + it('should perform element-wise (dense matrix .* sparse matrix) multiplication', function() { + approx.deepEqual(dotMultiply(matrix([[1,2],[3,4]]), sparse([[5,6],[7,8]])), sparse([[5,12],[21,32]])); + }); + + it('should throw an error if arrays are of different sizes', function() { + assert.throws(function () {dotMultiply(a, c)}); + assert.throws(function () {dotMultiply(d, a)}); + assert.throws(function () {dotMultiply(d, b)}); + assert.throws(function () {dotMultiply(d, c)}); + assert.throws(function () {dotMultiply(c, b)}); + }); }); + + describe('SparseMatrix', function () { - it('should throw an error if matrices are of different sizes', function() { - assert.throws(function () {dotMultiply(a, c)}); - assert.throws(function () {dotMultiply(d, a)}); - assert.throws(function () {dotMultiply(d, b)}); - assert.throws(function () {dotMultiply(d, c)}); - assert.throws(function () {dotMultiply(c, b)}); + var a = sparse([[1,0],[3,4]]); + var b = sparse([[5,6],[0,8]]); + var c = sparse([[5],[6]]); + var d = sparse([[5,6]]); + + it('should multiply a all elements in a sparse matrix by a number', function() { + // matrix, array, range + approx.deepEqual(dotMultiply(a, 3), sparse([[3,0],[9,12]])); + approx.deepEqual(dotMultiply(3, a), sparse([[3,0],[9,12]])); + approx.deepEqual(dotMultiply(sparse([1,2,3,4]), 2), sparse([2, 4, 6, 8])); + approx.deepEqual(dotMultiply(2, sparse([1,2,3,4])), sparse([2, 4, 6, 8])); + }); + + it('should perform element-wise (sparse matrix .* array) multiplication', function() { + approx.deepEqual(dotMultiply(a, [[5,6],[0,8]]), sparse([[5,0],[0,32]])); + approx.deepEqual(dotMultiply(sparse([[1,2],[3,4]]), [[5,6],[7,8]]), sparse([[5,12],[21,32]])); + }); + + it('should perform element-wise (sparse matrix .* dense matrix) multiplication', function() { + approx.deepEqual(dotMultiply(sparse([[1,2],[3,4]]), matrix([[5,6],[7,8]])), sparse([[5,12],[21,32]])); + }); + + it('should perform element-wise (sparse matrix .* sparse matrix) multiplication', function() { + approx.deepEqual(dotMultiply(sparse([[0,2],[3,4]]), sparse([[5,6],[0,8]])), sparse([[0,12],[0,32]])); + }); + + it('should throw an error if arrays are of different sizes', function() { + assert.throws(function () {dotMultiply(a, c)}); + assert.throws(function () {dotMultiply(d, a)}); + assert.throws(function () {dotMultiply(d, b)}); + assert.throws(function () {dotMultiply(d, c)}); + assert.throws(function () {dotMultiply(c, b)}); + }); }); it('should throw an error in case of invalid number of arguments', function() { diff --git a/test/function/arithmetic/dotPow.test.js b/test/function/arithmetic/dotPow.test.js index 10d3e9c64..c9872f921 100644 --- a/test/function/arithmetic/dotPow.test.js +++ b/test/function/arithmetic/dotPow.test.js @@ -1,12 +1,11 @@ // test exp var assert = require('assert'), approx = require('../../../tools/approx'), - error = require('../../../lib/error/index'), math = require('../../../index'), complex = math.complex, matrix = math.matrix, + sparse = math.sparse, unit = math.unit, - range = math.range, dotPow = math.dotPow; describe('dotPow', function() { @@ -44,8 +43,8 @@ describe('dotPow', function() { }); it('should throw an error in case of invalid number of arguments', function() { - assert.throws(function () {dotPow(1)}, /TypeError: Too few arguments/); - assert.throws(function () {dotPow(1, 2, 3)}, /TypeError: Too many arguments/); + assert.throws(function () {dotPow(1);}, /TypeError: Too few arguments/); + assert.throws(function () {dotPow(1, 2, 3);}, /TypeError: Too many arguments/); }); it('should elevate a complex number to the given power', function() { @@ -86,26 +85,96 @@ describe('dotPow', function() { }); it('should throw an error with units', function() { - assert.throws(function () {dotPow(unit('5cm'))}); + assert.throws(function () {dotPow(unit('5cm'));}); }); it('should throw an error with strings', function() { - assert.throws(function () {dotPow('text')}); + assert.throws(function () {dotPow('text');}); }); - it('should elevate each element in a matrix to the given power', function() { - var a = [[1,2],[3,4]]; - var res = [[1,4],[9,16]]; - approx.deepEqual(dotPow(a, 2), res); - approx.deepEqual(dotPow(a, 2.5), [[1,5.65685424949238], [15.58845726811990, 32]]); - approx.deepEqual(dotPow(3, [2,3]), [9,27]); - approx.deepEqual(dotPow(matrix(a), 2), matrix(res)); - approx.deepEqual(dotPow([[1,2,3],[4,5,6]],2), [[1,4,9],[16,25,36]]); + describe('Array', function () { + + it('should elevate array .^ scalar', function () { + approx.deepEqual(dotPow([[1,2],[0,4]], 2), [[1,4],[0,16]]); + approx.deepEqual(dotPow([[1,2],[0,4]], 2.5), [[1,5.65685424949238], [0, 32]]); + approx.deepEqual(dotPow([[1,2,3],[4,5,0]], 2), [[1,4,9],[16,25,0]]); + }); + + it('should elevate scalar .^ array', function () { + approx.deepEqual(dotPow(2, [[1,2],[0,4]]), [[2,4],[1,16]]); + approx.deepEqual(dotPow(2.5, [[1,2],[0,4]]), [[2.5, 6.25], [1, 39.0625]]); + approx.deepEqual(dotPow(2, [[1,2,3],[4,5,0]]), [[2,4,8],[16,32,1]]); + }); + + it('should elevate array .^ array', function () { + approx.deepEqual(dotPow([[1,2,0],[0,1,4]], [[2,1,0],[4,1,0]]), [[1,2,1],[0,1,1]]); + }); + + it('should elevate array .^ dense matrix', function () { + approx.deepEqual(dotPow([[1,2,0],[0,1,4]], matrix([[2,1,0],[4,1,0]])), matrix([[1,2,1],[0,1,1]])); + }); + + it('should elevate array .^ sparse matrix', function () { + approx.deepEqual(dotPow([[1,2,0],[0,1,4]], sparse([[2,1,0],[4,1,0]])), matrix([[1,2,1],[0,1,1]])); + }); + }); + + describe('DenseMatrix', function () { + + it('should elevate dense matrix .^ scalar', function () { + approx.deepEqual(dotPow(matrix([[1,2],[0,4]]), 2), matrix([[1,4],[0,16]])); + approx.deepEqual(dotPow(matrix([[1,2],[0,4]]), 2.5), matrix([[1,5.65685424949238], [0, 32]])); + approx.deepEqual(dotPow(matrix([[1,2,3],[4,5,0]]), 2), matrix([[1,4,9],[16,25,0]])); + }); + + it('should elevate scaler .^ dense matrix', function () { + approx.deepEqual(dotPow(2, matrix([[1,2],[0,4]])), matrix([[2,4],[1,16]])); + approx.deepEqual(dotPow(2.5, matrix([[1,2],[0,4]])), matrix([[2.5, 6.25], [1, 39.0625]])); + approx.deepEqual(dotPow(2, matrix([[1,2,3],[4,5,0]])), matrix([[2,4,8],[16,32,1]])); + }); + + it('should elevate dense matrix .^ array', function () { + approx.deepEqual(dotPow(matrix([[1,2,0],[0,1,4]]), [[2,1,0],[4,1,0]]), matrix([[1,2,1],[0,1,1]])); + }); + + it('should elevate dense matrix .^ dense matrix', function () { + approx.deepEqual(dotPow(matrix([[1,2,0],[0,1,4]]), matrix([[2,1,0],[4,1,0]])), matrix([[1,2,1],[0,1,1]])); + }); + + it('should elevate dense matrix .^ sparse matrix', function () { + approx.deepEqual(dotPow(matrix([[1,2,0],[0,1,4]]), sparse([[2,1,0],[4,1,0]])), matrix([[1,2,1],[0,1,1]])); + }); + }); + + describe('SparseMatrix', function () { + + it('should elevate sparse matrix .^ scalar', function () { + approx.deepEqual(dotPow(sparse([[1,2],[0,4]]), 2), sparse([[1,4],[0,16]])); + approx.deepEqual(dotPow(sparse([[1,2],[0,4]]), 2.5), sparse([[1,5.65685424949238], [0, 32]])); + approx.deepEqual(dotPow(sparse([[1,2,3],[4,5,0]]), 2), sparse([[1,4,9],[16,25,0]])); + }); + + it('should elevate scalar .^ sparse matrix', function () { + approx.deepEqual(dotPow(2, sparse([[1,2],[0,4]])), matrix([[2,4],[1,16]])); + approx.deepEqual(dotPow(2.5, sparse([[1,2],[0,4]])), matrix([[2.5, 6.25], [1, 39.0625]])); + approx.deepEqual(dotPow(2, sparse([[1,2,3],[4,5,0]])), matrix([[2,4,8],[16,32,1]])); + }); + + it('should elevate sparse matrix .^ array', function () { + approx.deepEqual(dotPow(sparse([[1,2,0],[0,1,4]]), [[2,1,0],[4,1,0]]), matrix([[1,2,1],[0,1,1]])); + }); + + it('should elevate sparse matrix .^ dense matrix', function () { + approx.deepEqual(dotPow(sparse([[1,2,0],[0,1,4]]), matrix([[2,1,0],[4,1,0]])), matrix([[1,2,1],[0,1,1]])); + }); + + it('should elevate sparse matrix .^ sparse matrix', function () { + approx.deepEqual(dotPow(sparse([[1,2,0],[0,1,4]]), sparse([[2,1,0],[4,1,0]])), matrix([[1,2,1],[0,1,1]])); + }); }); it('should LaTeX dotPow', function () { var expression = math.parse('dotPow([1,2],[3,4])'); assert.equal(expression.toTex(), '\\left(\\begin{bmatrix}1\\\\2\\\\\\end{bmatrix}.^\\wedge\\begin{bmatrix}3\\\\4\\\\\\end{bmatrix}\\right)'); }); - }); diff --git a/test/function/arithmetic/exp.test.js b/test/function/arithmetic/exp.test.js index 525b52eb4..4db1e562a 100644 --- a/test/function/arithmetic/exp.test.js +++ b/test/function/arithmetic/exp.test.js @@ -1,15 +1,15 @@ // test exp var assert = require('assert'), approx = require('../../../tools/approx'), - error = require('../../../lib/error/index'), math = require('../../../index'), complex = math.complex, matrix = math.matrix, + sparse = math.sparse, unit = math.unit, - range = math.range, exp = math.exp; describe('exp', function() { + it('should exponentiate a boolean', function () { approx.equal(exp(true), 2.71828182845905); approx.equal(exp(false), 1); @@ -37,8 +37,8 @@ describe('exp', function() { }); it('should throw an error if there\'s wrong number of arguments', function() { - assert.throws(function () {exp()}, /TypeError: Too few arguments/); - assert.throws(function () {exp(1, 2)}, /TypeError: Too many arguments/); + assert.throws(function () {exp();}, /TypeError: Too few arguments/); + assert.throws(function () {exp(1, 2);}, /TypeError: Too many arguments/); }); it('should exponentiate a complex number correctly', function() { @@ -64,24 +64,26 @@ describe('exp', function() { }); it('should throw an error on a unit', function() { - assert.throws(function () {exp(unit('5cm'))}); + assert.throws(function () {exp(unit('5cm'));}); }); it('should throw an error with a string', function() { - assert.throws(function () {exp('text')}); + assert.throws(function () {exp('text');}); }); it('should exponentiate matrices, arrays and ranges correctly', function() { - var res = [1, 2.71828182845905, 7.38905609893065, 20.0855369231877]; - approx.deepEqual(exp([0,1,2,3]), res); - approx.deepEqual(exp(matrix([0,1,2,3])), matrix(res)); - approx.deepEqual(exp(matrix([[0,1],[2,3]])), - matrix([[1, 2.71828182845905], [7.38905609893065, 20.0855369231877]])); + // array + approx.deepEqual(exp([0, 1, 2, 3]), [1, 2.71828182845905, 7.38905609893065, 20.0855369231877]); + approx.deepEqual(exp([[0, 1], [2, 3]]), [[1, 2.71828182845905], [7.38905609893065, 20.0855369231877]]); + // dense matrix + approx.deepEqual(exp(matrix([0, 1, 2, 3])), matrix([1, 2.71828182845905, 7.38905609893065, 20.0855369231877])); + approx.deepEqual(exp(matrix([[0, 1], [2, 3]])), matrix([[1, 2.71828182845905], [7.38905609893065, 20.0855369231877]])); + // sparse matrix, TODO: it should return a dense matrix + approx.deepEqual(exp(sparse([[0, 1], [2, 3]])), sparse([[1, 2.71828182845905], [7.38905609893065, 20.0855369231877]])); }); it('should LaTeX exp', function () { var expression = math.parse('exp(0)'); assert.equal(expression.toTex(), '\\exp\\left(0\\right)'); }); - }); diff --git a/test/function/arithmetic/gcd.test.js b/test/function/arithmetic/gcd.test.js index 474e79e34..3fd99b120 100644 --- a/test/function/arithmetic/gcd.test.js +++ b/test/function/arithmetic/gcd.test.js @@ -1,10 +1,12 @@ // test gcd var assert = require('assert'), - error = require('../../../lib/error/index'), math = require('../../../index'), + matrix = math.matrix, + sparse = math.sparse, gcd = math.gcd; describe('gcd', function() { + it('should find the greatest common divisor of two or more numbers', function() { assert.strictEqual(gcd(12, 8), 4); assert.strictEqual(gcd(8, 12), 4); @@ -75,7 +77,7 @@ describe('gcd', function() { it('should throw an error for non-integer numbers', function() { assert.throws(function () {gcd(2, 4.1); }, /Parameters in function gcd must be integer numbers/); assert.throws(function () {gcd(2.3, 4); }, /Parameters in function gcd must be integer numbers/); - }) + }); it('should throw an error with complex numbers', function() { assert.throws(function () {gcd(math.complex(1,3),2); }, /TypeError: Unexpected type of argument/); @@ -89,14 +91,69 @@ describe('gcd', function() { it('should throw an error with units', function() { assert.throws(function () { gcd(math.unit('5cm'), 2); }, /TypeError: Unexpected type of argument/); }); + + describe('Array', function () { + + it('should find the greatest common divisor array - scalar', function() { + assert.deepEqual(gcd([5, 18, 3], 3), [1, 3, 3]); + assert.deepEqual(gcd(3, [5, 18, 3]), [1, 3, 3]); + }); + + it('should find the greatest common divisor array - array', function() { + assert.deepEqual(gcd([5, 2, 3], [25, 3, 6]), [5, 1, 3]); + }); + + it('should find the greatest common divisor array - dense matrix', function() { + assert.deepEqual(gcd([5, 2, 3], matrix([25, 3, 6])), matrix([5, 1, 3])); + }); - it('should find the greatest common divisor element-wise in a matrix', function() { - assert.deepEqual(gcd([5,2,3], [25,3,6]), [5, 1, 3]); + it('should find the greatest common divisor array - sparse matrix', function() { + assert.deepEqual(gcd([[5, 2, 3], [3, 2, 5]], sparse([[0, 3, 6], [6, 0, 25]])), matrix([[5, 1, 3], [3, 2, 5]])); + }); + }); + + describe('DenseMatrix', function () { + + it('should find the greatest common divisor dense matrix - scalar', function() { + assert.deepEqual(gcd(matrix([5, 18, 3]), 3), matrix([1, 3, 3])); + assert.deepEqual(gcd(3, matrix([5, 18, 3])), matrix([1, 3, 3])); + }); + + it('should find the greatest common divisor dense matrix - array', function() { + assert.deepEqual(gcd(matrix([5, 2, 3]), [25, 3, 6]), matrix([5, 1, 3])); + }); + + it('should find the greatest common divisor dense matrix - dense matrix', function() { + assert.deepEqual(gcd(matrix([5, 2, 3]), matrix([25, 3, 6])), matrix([5, 1, 3])); + }); + + it('should find the greatest common divisor dense matrix - sparse matrix', function() { + assert.deepEqual(gcd(matrix([[5, 2, 3], [3, 2, 5]]), sparse([[0, 3, 6], [6, 0, 25]])), matrix([[5, 1, 3], [3, 2, 5]])); + }); + }); + + describe('SparseMatrix', function () { + + it('should find the greatest common divisor sparse matrix - scalar', function() { + assert.deepEqual(gcd(sparse([[5, 0, 3], [0, 18, 0]]), 3), matrix([[1, 3, 3], [3, 3, 3]])); + assert.deepEqual(gcd(3, sparse([[5, 0, 3], [0, 18, 0]])), matrix([[1, 3, 3], [3, 3, 3]])); + }); + + it('should find the greatest common divisor sparse matrix - array', function() { + assert.deepEqual(gcd(sparse([[5, 2, 3], [3, 2, 5]]), [[0, 3, 6], [6, 0, 25]]), matrix([[5, 1, 3], [3, 2, 5]])); + }); + + it('should find the greatest common divisor sparse matrix - dense matrix', function() { + assert.deepEqual(gcd(sparse([[5, 2, 3], [3, 2, 5]]), matrix([[0, 3, 6], [6, 0, 25]])), matrix([[5, 1, 3], [3, 2, 5]])); + }); + + it('should find the greatest common divisor sparse matrix - sparse matrix', function() { + assert.deepEqual(gcd(sparse([[5, 2, 3], [3, 2, 5]]), sparse([[0, 3, 6], [6, 0, 25]])), sparse([[5, 1, 3], [3, 2, 5]])); + }); }); it('should LaTeX gcd', function () { var expression = math.parse('gcd(2,3)'); assert.equal(expression.toTex(), '\\gcd\\left(2,3\\right)'); }); - }); diff --git a/test/function/arithmetic/lcm.test.js b/test/function/arithmetic/lcm.test.js index 464c0061c..9c0ffa1b0 100644 --- a/test/function/arithmetic/lcm.test.js +++ b/test/function/arithmetic/lcm.test.js @@ -1,6 +1,7 @@ var assert = require('assert'), - error = require('../../../lib/error/index'), math = require('../../../index'), + matrix = math.matrix, + sparse = math.sparse, lcm = math.lcm; describe('lcm', function() { @@ -61,7 +62,7 @@ describe('lcm', function() { it('should throw an error for non-integer numbers', function() { assert.throws(function () {lcm(2, 4.1); }, /Parameters in function lcm must be integer numbers/); assert.throws(function () {lcm(2.3, 4); }, /Parameters in function lcm must be integer numbers/); - }) + }); it('should throw an error with complex numbers', function() { assert.throws(function () {lcm(math.complex(1,3),2); }, TypeError, 'Function lcm(complex, number) not supported'); @@ -76,13 +77,68 @@ describe('lcm', function() { assert.throws(function () { lcm(math.unit('5cm'), 2); }, TypeError, 'Function lcm(unit, number) not supported'); }); - it('should perform element-wise lcm on two or more matrices of the same size', function() { - assert.deepEqual(lcm([5,2,3], [25,3,6]), [25, 6, 6]); + describe('Array', function () { + + it('should find the greatest common divisor array - scalar', function() { + assert.deepEqual(lcm([5, 18, 3], 3), [15, 18, 3]); + assert.deepEqual(lcm(3, [5, 18, 3]), [15, 18, 3]); + }); + + it('should find the greatest common divisor array - array', function() { + assert.deepEqual(lcm([5, 2, 3], [25, 3, 6]), [25, 6, 6]); + }); + + it('should find the greatest common divisor array - dense matrix', function() { + assert.deepEqual(lcm([5, 2, 3], matrix([25, 3, 6])), matrix([25, 6, 6])); + }); + + it('should find the greatest common divisor array - sparse matrix', function() { + assert.deepEqual(lcm([[5, 2, 3], [3, 2, 5]], sparse([[0, 3, 6], [6, 0, 25]])), sparse([[0, 6, 6], [6, 0, 25]])); + }); + }); + + describe('DenseMatrix', function () { + + it('should find the greatest common divisor dense matrix - scalar', function() { + assert.deepEqual(lcm(matrix([5, 18, 3]), 3), matrix([15, 18, 3])); + assert.deepEqual(lcm(3, matrix([5, 18, 3])), matrix([15, 18, 3])); + }); + + it('should find the greatest common divisor dense matrix - array', function() { + assert.deepEqual(lcm(matrix([5, 2, 3]), [25, 3, 6]), matrix([25, 6, 6])); + }); + + it('should find the greatest common divisor dense matrix - dense matrix', function() { + assert.deepEqual(lcm(matrix([5, 2, 3]), matrix([25, 3, 6])), matrix([25, 6, 6])); + }); + + it('should find the greatest common divisor dense matrix - sparse matrix', function() { + assert.deepEqual(lcm(matrix([[5, 2, 3], [3, 2, 5]]), sparse([[0, 3, 6], [6, 0, 25]])), sparse([[0, 6, 6], [6, 0, 25]])); + }); + }); + + describe('SparseMatrix', function () { + + it('should find the greatest common divisor sparse matrix - scalar', function() { + assert.deepEqual(lcm(sparse([[5, 0, 3], [0, 18, 0]]), 3), sparse([[15, 0, 3], [0, 18, 0]])); + assert.deepEqual(lcm(3, sparse([[5, 0, 3], [0, 18, 0]])), sparse([[15, 0, 3], [0, 18, 0]])); + }); + + it('should find the greatest common divisor sparse matrix - array', function() { + assert.deepEqual(lcm(sparse([[5, 2, 3], [3, 2, 5]]), [[0, 3, 6], [6, 0, 25]]), sparse([[0, 6, 6], [6, 0, 25]])); + }); + + it('should find the greatest common divisor sparse matrix - dense matrix', function() { + assert.deepEqual(lcm(sparse([[5, 2, 3], [3, 2, 5]]), matrix([[0, 3, 6], [6, 0, 25]])), sparse([[0, 6, 6], [6, 0, 25]])); + }); + + it('should find the greatest common divisor sparse matrix - sparse matrix', function() { + assert.deepEqual(lcm(sparse([[5, 2, 3], [3, 2, 5]]), sparse([[0, 3, 6], [6, 0, 25]])), sparse([[0, 6, 6], [6, 0, 25]])); + }); }); it('should LaTeX lcm', function () { var expression = math.parse('lcm(2,3)'); assert.equal(expression.toTex(), '\\mathrm{lcm}\\left(2,3\\right)'); }); - }); diff --git a/test/function/arithmetic/mod.test.js b/test/function/arithmetic/mod.test.js index 7a9b0e7fb..508b244c9 100644 --- a/test/function/arithmetic/mod.test.js +++ b/test/function/arithmetic/mod.test.js @@ -4,10 +4,11 @@ var approx = require('../../../tools/approx'); var math = require('../../../index'); var bignumber = math.bignumber; var matrix = math.matrix; -var range = math.range; +var sparse = math.sparse; var mod = math.mod; describe('mod', function() { + it('should calculate the modulus of booleans correctly', function () { assert.equal(mod(true, true), 0); assert.equal(mod(false, true), 0); @@ -38,17 +39,17 @@ describe('mod', function() { }); it('should throw an error if the modulus is negative', function() { - assert.throws(function () {mod(10, -4)}); + assert.throws(function () {mod(10, -4);}); }); it('should throw an error if used with wrong number of arguments', function() { - assert.throws(function () {mod(1)}, /TypeError: Too few arguments/); - assert.throws(function () {mod(1,2,3)}, /TypeError: Too many arguments/); + assert.throws(function () {mod(1);}, /TypeError: Too few arguments/); + assert.throws(function () {mod(1,2,3);}, /TypeError: Too many arguments/); }); it('should throw an error if used with wrong type of arguments', function() { - assert.throws(function () {mod(1, 'string')}, /TypeError: Unexpected type of argument/); - assert.throws(function () {mod('string', bignumber(2))}, /TypeError: Unexpected type of argument/); + assert.throws(function () {mod(1, 'string');}, /TypeError: Unexpected type of argument/); + assert.throws(function () {mod('string', bignumber(2));}, /TypeError: Unexpected type of argument/); }); it('should calculate the modulus of bignumbers', function() { @@ -75,8 +76,8 @@ describe('mod', function() { assert.deepEqual(mod(bignumber(0), 3), bignumber(0)); assert.deepEqual(mod(bignumber(7), 0), bignumber(7)); - assert.throws(function () {mod(7/3, bignumber(2))}, /TypeError: Cannot implicitly convert a number with >15 significant digits to BigNumber/); - assert.throws(function () {mod(bignumber(7).div(3), 1/3)}, /TypeError: Cannot implicitly convert a number with >15 significant digits to BigNumber/); + assert.throws(function () {mod(7/3, bignumber(2));}, /TypeError: Cannot implicitly convert a number with >15 significant digits to BigNumber/); + assert.throws(function () {mod(bignumber(7).div(3), 1/3);}, /TypeError: Cannot implicitly convert a number with >15 significant digits to BigNumber/); }); it('should calculate the modulus of mixed booleans and bignumbers', function() { @@ -87,24 +88,78 @@ describe('mod', function() { }); it('should throw an error if used on complex numbers', function() { - assert.throws(function () {mod(math.complex(1,2), 3)}, TypeError); - assert.throws(function () {mod(3, math.complex(1,2))}, TypeError); - assert.throws(function () {mod(bignumber(3), math.complex(1,2))}, TypeError); + assert.throws(function () {mod(math.complex(1,2), 3);}, TypeError); + assert.throws(function () {mod(3, math.complex(1,2));}, TypeError); + assert.throws(function () {mod(bignumber(3), math.complex(1,2));}, TypeError); }); it('should an throw an error if used on a string', function() { - assert.throws(function () {mod('string', 3)}, TypeError); - assert.throws(function () {mod(5, 'string')}, TypeError); + assert.throws(function () {mod('string', 3);}, TypeError); + assert.throws(function () {mod(5, 'string');}, TypeError); }); - it('should perform element-wise modulus on a matrix', function() { - approx.deepEqual(mod([-4,-3,-2,-1,0,1,2,3,4], 3), [2,0,1,2,0,1,2,0,1]); - approx.deepEqual(mod(matrix([-4,-3,-2,-1,0,1,2,3,4]), 3), matrix([2,0,1,2,0,1,2,0,1])); + describe('Array', function () { + + it('should perform element-wise modulus on array and scalar', function() { + approx.deepEqual(mod([[-4, -3, 0, -1], [0, 1, 2, 3]], 3), [[2, 0, 0, 2], [0, 1, 2, 0]]); + approx.deepEqual(mod(3, [[4, 3], [2, 1]]), [[3, 0], [1, 0]]); + }); + + it('should perform element-wise modulus on array and array', function() { + approx.deepEqual(mod([[-40, -31], [11, -23]], [[3, 7], [1, 3]]), [[2, 4], [0, 1]]); + }); + + it('should perform element-wise modulus on array and dense matrix', function() { + approx.deepEqual(mod([[-40, -31], [11, -23]], matrix([[3, 7], [1, 3]])), matrix([[2, 4], [0, 1]])); + }); + + it('should perform element-wise modulus on array and sparse matrix', function() { + approx.deepEqual(mod([[-40, -31], [11, -23]], sparse([[3, 7], [1, 3]])), matrix([[2, 4], [0, 1]])); + }); }); + describe('DenseMatrix', function () { + + it('should perform element-wise modulus on dense matrix and scalar', function() { + approx.deepEqual(mod(matrix([[-4, -3, 0, -1], [0, 1, 2, 3]]), 3), matrix([[2, 0, 0, 2], [0, 1, 2, 0]])); + approx.deepEqual(mod(3, matrix([[4, 3], [2, 1]])), matrix([[3, 0], [1, 0]])); + }); + + it('should perform element-wise modulus on dense matrix and array', function() { + approx.deepEqual(mod(matrix([[-40, -31], [11, -23]]), [[3, 7], [1, 3]]), matrix([[2, 4], [0, 1]])); + }); + + it('should perform element-wise modulus on dense matrix and dense matrix', function() { + approx.deepEqual(mod(matrix([[-40, -31], [11, -23]]), matrix([[3, 7], [1, 3]])), matrix([[2, 4], [0, 1]])); + }); + + it('should perform element-wise modulus on dense matrix and sparse matrix', function() { + approx.deepEqual(mod(matrix([[-40, -31], [11, -23]]), sparse([[3, 7], [1, 3]])), matrix([[2, 4], [0, 1]])); + }); + }); + + describe('SparseMatrix', function () { + + it('should perform element-wise modulus on sparse matrix and scalar', function() { + approx.deepEqual(mod(sparse([[-4, -3, 0, -1], [0, 1, 2, 3]]), 3), sparse([[2, 0, 0, 2], [0, 1, 2, 0]])); + approx.deepEqual(mod(3, sparse([[4, 3], [2, 1]])), matrix([[3, 0], [1, 0]])); + }); + + it('should perform element-wise modulus on sparse matrix and array', function() { + approx.deepEqual(mod(sparse([[-40, -31], [11, -23]]), [[3, 7], [1, 3]]), sparse([[2, 4], [0, 1]])); + }); + + it('should perform element-wise modulus on sparse matrix and dense matrix', function() { + approx.deepEqual(mod(sparse([[-40, -31], [11, -23]]), matrix([[3, 7], [1, 3]])), sparse([[2, 4], [0, 1]])); + }); + + it('should perform element-wise modulus on sparse matrix and sparse matrix', function() { + approx.deepEqual(mod(sparse([[-40, -31], [11, -23]]), sparse([[3, 7], [1, 3]])), sparse([[2, 4], [0, 1]])); + }); + }); + it('should LaTeX mod', function () { var expression = math.parse('mod(11,2)'); assert.equal(expression.toTex(), '\\left(11\\mod2\\right)'); }); - }); diff --git a/test/function/arithmetic/multiply.test.js b/test/function/arithmetic/multiply.test.js index d660734de..f024fab98 100644 --- a/test/function/arithmetic/multiply.test.js +++ b/test/function/arithmetic/multiply.test.js @@ -367,6 +367,20 @@ describe('multiply', function() { ]); }); + it('should multiply matrix x matrix, number datatype', function() { + var m1 = math.matrix([[1, 2], [3, 4]], 'dense', 'number'); + var m2 = math.matrix([[5, 6], [7, 8]], 'dense', 'number'); + + var r = multiply(m1, m2); + assert(r.datatype() === 'number'); + assert.deepEqual( + r.valueOf(), + [ + [19, 22], + [43, 50] + ]); + }); + it('should multiply matrix x array', function() { var m = math.matrix([ [2, 0], @@ -581,6 +595,20 @@ describe('multiply', function() { [43, 50] ]); }); + + it('should multiply matrix x matrix, number datatype', function() { + var m1 = math.matrix([[1, 2], [3, 4]], 'sparse', 'number'); + var m2 = math.matrix([[5, 6], [7, 8]], 'sparse', 'number'); + + var r = multiply(m1, m2); + assert(r.datatype() === 'number'); + assert.deepEqual( + r.valueOf(), + [ + [19, 22], + [43, 50] + ]); + }); it('should multiply matrix x array', function() { var m = math.matrix([[2, 0], [4, 0]], 'sparse'); @@ -668,15 +696,16 @@ describe('multiply', function() { ], 'sparse'); var r = multiply(l, u); - + + assert(r.storage(), 'sparse'); approx.deepEqual( - r, - math.matrix([ + r.valueOf(), + [ [240, -2700, 6480, -4200], [-120, 1200, -2700, 1680], [0, 105, -420, 350], [16, -120, 240, -140] - ], 'sparse')); + ]); }); var a = matrix([[1,2],[3,4]], 'sparse'); @@ -696,6 +725,87 @@ describe('multiply', function() { approx.deepEqual(multiply(d, b), matrix([[67,78]], 'sparse')); approx.deepEqual(multiply(d, c), 61); }); + + it('should multiply two pattern matrices correctly', function() { + + var a = new math.type.SparseMatrix({ + values: undefined, + index: [0, 1, 2, 0], + ptr: [0, 2, 3, 4], + size: [3, 3] + }); + + var b = new math.type.SparseMatrix({ + values: undefined, + index: [0, 1, 2, 1], + ptr: [0, 3, 3, 4], + size: [3, 3] + }); + + var c = multiply(a, b); + + assert.deepEqual( + c.valueOf(), + [ + [1, 0, 0], + [1, 0, 0], + [1, 0, 1] + ]); + }); + + it('should multiply pattern and value matrices correctly', function() { + + var a = new math.type.SparseMatrix({ + values: undefined, + index: [0, 1, 2, 0], + ptr: [0, 2, 3, 4], + size: [3, 3] + }); + + var b = new math.type.SparseMatrix({ + values: [1, 2, 3, 4], + index: [0, 1, 2, 1], + ptr: [0, 3, 3, 4], + size: [3, 3] + }); + + var c = multiply(a, b); + + assert.deepEqual( + c.valueOf(), + [ + [1, 0, 0], + [1, 0, 0], + [1, 0, 1] + ]); + }); + + it('should multiply value and pattern matrices correctly', function() { + + var a = new math.type.SparseMatrix({ + values: [1, 2, 3, 4], + index: [0, 1, 2, 0], + ptr: [0, 2, 3, 4], + size: [3, 3] + }); + + var b = new math.type.SparseMatrix({ + values: undefined, + index: [0, 1, 2, 1], + ptr: [0, 3, 3, 4], + size: [3, 3] + }); + + var c = multiply(a, b); + + assert.deepEqual( + c.valueOf(), + [ + [1, 0, 0], + [1, 0, 0], + [1, 0, 1] + ]); + }); }); describe('Matrix Market', function () { diff --git a/test/function/arithmetic/nthRoot.test.js b/test/function/arithmetic/nthRoot.test.js index 505b2e6f9..ef41ebf27 100644 --- a/test/function/arithmetic/nthRoot.test.js +++ b/test/function/arithmetic/nthRoot.test.js @@ -1,17 +1,16 @@ // test nthRoot var assert = require('assert'); var approx = require('../../../tools/approx'); -var error = require('../../../lib/error/index'); var math = require('../../../index'); -var complex = math.complex; var matrix = math.matrix; +var sparse = math.sparse; var unit = math.unit; -var range = math.range; var nthRoot = math.nthRoot; var big = math.bignumber; describe('nthRoot', function() { + it('should return the nthRoot of a boolean value', function () { assert.equal(nthRoot(true), 1); assert.equal(nthRoot(false), 0); @@ -51,20 +50,19 @@ describe('nthRoot', function() { }); it('should throw an error when n is zero', function() { - assert.throws(function () {nthRoot(4, 0)}, /Root must be non-zero/); + assert.throws(function () {nthRoot(4, 0);}, /Root must be non-zero/); }); it('should throw an error when value is negative and root is even', function() { - assert.throws(function () {nthRoot(-27, 2)}, /Root must be odd when a is negative/); - assert.throws(function () {nthRoot(-27, 2.5)}, /Root must be odd when a is negative/); + assert.throws(function () {nthRoot(-27, 2);}, /Root must be odd when a is negative/); + assert.throws(function () {nthRoot(-27, 2.5);}, /Root must be odd when a is negative/); }); it('should throw an error if invalid number of arguments', function() { - assert.throws(function () {nthRoot()}, /TypeError: Too few arguments/); - assert.throws(function () {nthRoot(1, 2, 3)}, /TypeError: Too many arguments/); + assert.throws(function () {nthRoot();}, /TypeError: Too few arguments/); + assert.throws(function () {nthRoot(1, 2, 3);}, /TypeError: Too many arguments/); }); - it('should return the nthRoot of bignumbers', function() { assert.deepEqual(nthRoot(big(4)), big(2)); assert.deepEqual(nthRoot(big(9)), big(3)); @@ -89,29 +87,80 @@ describe('nthRoot', function() { }); it('should throw an error when used on a complex value', function() { - assert.throws(function () {nthRoot(math.complex(2,3))}); - assert.throws(function () {nthRoot(math.complex(2,3), 3)}); + assert.throws(function () {nthRoot(math.complex(2,3));}); + assert.throws(function () {nthRoot(math.complex(2,3), 3);}); }); it('should throw an error when used on a unit', function() { - assert.throws(function () {nthRoot(unit('5cm'))}); + assert.throws(function () {nthRoot(unit('5cm'));}); }); it('should throw an error when used on a string', function() { - assert.throws(function () {nthRoot('text')}); + assert.throws(function () {nthRoot('text');}); }); - it('should return the nthRoot of each element of a matrix', function() { - var x = [2, 3, 4]; - var a = [8, 27, 64]; - var n = 3; - approx.deepEqual(nthRoot(a, n), x); - approx.deepEqual(nthRoot(matrix(a), n), matrix(x)); + describe('Array', function () { + + it('should return the nthRoot for array - scalar', function () { + approx.deepEqual(nthRoot([8, 27, 64], 3), [2, 3, 4]); + approx.deepEqual(nthRoot(64, [2, 3, 8]), [8, 4, 1.6817928305074290860622509524664]); + }); + + it('should return the nthRoot for array - array', function () { + approx.deepEqual(nthRoot([[64, 3125], [0, -1]], [[3, 5], [1, 3]]), [[4, 5], [0, -1]]); + }); + + it('should return the nthRoot for array - dense matrix', function () { + approx.deepEqual(nthRoot([[64, 3125], [0, -1]], matrix([[3, 5], [1, 3]])), matrix([[4, 5], [0, -1]])); + }); + + it('should return the nthRoot for array - sparse matrix', function () { + approx.deepEqual(nthRoot([[64, 3125], [0, -1]], sparse([[3, 5], [1, 3]])), matrix([[4, 5], [0, -1]])); + }); + }); + + describe('DenseMatrix', function () { + + it('should return the nthRoot for dense matrix - scalar', function () { + approx.deepEqual(nthRoot(matrix([8, 27, 64]), 3), matrix([2, 3, 4])); + approx.deepEqual(nthRoot(64, matrix([2, 3, 8])), matrix([8, 4, 1.6817928305074290860622509524664])); + }); + + it('should return the nthRoot for dense matrix - array', function () { + approx.deepEqual(nthRoot(matrix([[64, 3125], [0, -1]]), [[3, 5], [1, 3]]), matrix([[4, 5], [0, -1]])); + }); + + it('should return the nthRoot for dense matrix - dense matrix', function () { + approx.deepEqual(nthRoot(matrix([[64, 3125], [0, -1]]), matrix([[3, 5], [1, 3]])), matrix([[4, 5], [0, -1]])); + }); + + it('should return the nthRoot for dense matrix - sparse matrix', function () { + approx.deepEqual(nthRoot(matrix([[64, 3125], [0, -1]]), sparse([[3, 5], [1, 3]])), matrix([[4, 5], [0, -1]])); + }); + }); + + describe('SparseMatrix', function () { + + it('should return the nthRoot for sparse matrix - scalar', function () { + approx.deepEqual(nthRoot(sparse([[8, 27], [0, 64]]), 3), sparse([[2, 3], [0, 4]])); + approx.deepEqual(nthRoot(64, sparse([[2, 3], [1, 8]])), sparse([[8, 4], [64, 1.6817928305074290860622509524664]])); + }); + + it('should return the nthRoot for sparse matrix - array', function () { + approx.deepEqual(nthRoot(sparse([[64, 3125], [0, -1]]), [[3, 5], [1, 3]]), sparse([[4, 5], [0, -1]])); + }); + + it('should return the nthRoot for sparse matrix - dense matrix', function () { + approx.deepEqual(nthRoot(sparse([[64, 3125], [0, -1]]), matrix([[3, 5], [1, 3]])), sparse([[4, 5], [0, -1]])); + }); + + it('should return the nthRoot for sparse matrix - sparse matrix', function () { + approx.deepEqual(nthRoot(sparse([[64, 3125], [0, -1]]), sparse([[3, 5], [1, 3]])), sparse([[4, 5], [0, -1]])); + }); }); it('should LaTeX nthRoot', function () { var expression = math.parse('nthRoot(8,3)'); assert.equal(expression.toTex(), '\\sqrt[3]{8}'); }); - }); diff --git a/test/function/arithmetic/round.test.js b/test/function/arithmetic/round.test.js index 4bbed2ac4..5cb2f7dcd 100644 --- a/test/function/arithmetic/round.test.js +++ b/test/function/arithmetic/round.test.js @@ -1,9 +1,10 @@ // test round var assert = require('assert'), approx = require('../../../tools/approx'), - error = require('../../../lib/error/index'), math = require('../../../index'), bignumber = math.bignumber, + matrix = math.matrix, + sparse = math.sparse, round = math.round; describe('round', function() { @@ -83,6 +84,42 @@ describe('round', function() { assert.deepEqual(round([1.7,2.3]), [2,2]); assert.deepEqual(round(math.matrix([1.7,2.3])).valueOf(), [2, 2]); }); + + describe('Array', function () { + + it('should round array', function () { + assert.deepEqual(round([1.7, 2.3]), [2, 2]); + }); + + it('should round array and scalar', function () { + assert.deepEqual(round([1.7777, 2.3456], 3), [1.778, 2.346]); + assert.deepEqual(round(3.12385, [2, 3]), [3.12, 3.124]); + }); + }); + + describe('DenseMatrix', function () { + + it('should round dense matrix', function () { + assert.deepEqual(round(matrix([[1.7, 2.3], [8.987, -3.565]])), matrix([[2, 2], [9, -4]])); + }); + + it('should round dense matrix and scalar', function () { + assert.deepEqual(round(matrix([[1.7777, 2.3456],[-90.8272, 0]]), 3), matrix([[1.778, 2.346], [-90.827, 0]])); + assert.deepEqual(round(3.12385, matrix([[2, 3], [0, 2]])), matrix([[3.12, 3.124],[3, 3.12]])); + }); + }); + + describe('SparseMatrix', function () { + + it('should round sparse matrix', function () { + assert.deepEqual(round(sparse([[1.7, 0], [8.987, -3.565]])), sparse([[2, 0], [9, -4]])); + }); + + it('should round sparse matrix and scalar', function () { + assert.deepEqual(round(sparse([[1.7777, 2.3456],[-90.8272, 0]]), 3), sparse([[1.778, 2.346], [-90.827, 0]])); + assert.deepEqual(round(3.12385, sparse([[2, 3], [0, 2]])), matrix([[3.12, 3.124],[3, 3.12]])); + }); + }); it('should LaTeX round', function () { var expr1 = math.parse('round(1.1)'); diff --git a/test/function/arithmetic/subtract.test.js b/test/function/arithmetic/subtract.test.js index 33f95d74c..871ed5919 100644 --- a/test/function/arithmetic/subtract.test.js +++ b/test/function/arithmetic/subtract.test.js @@ -1,7 +1,6 @@ // test subtract var assert = require('assert'), approx = require('../../../tools/approx'), - error = require('../../../lib/error/index'), math = require('../../../index'), bignumber = math.bignumber, subtract = math.subtract; @@ -49,8 +48,8 @@ describe('subtract', function() { assert.deepEqual(subtract(bignumber(0.3), 0.2), bignumber(0.1)); assert.deepEqual(subtract(0.3, bignumber(0.2)), bignumber(0.1)); - assert.throws(function () {subtract(1/3, bignumber(1).div(3))}, /Cannot implicitly convert a number with >15 significant digits to BigNumber/); - assert.throws(function () {subtract(bignumber(1).div(3), 1/3)}, /Cannot implicitly convert a number with >15 significant digits to BigNumber/); + assert.throws(function () {subtract(1/3, bignumber(1).div(3));}, /Cannot implicitly convert a number with >15 significant digits to BigNumber/); + assert.throws(function () {subtract(bignumber(1).div(3), 1/3);}, /Cannot implicitly convert a number with >15 significant digits to BigNumber/); }); it('should subtract mixed booleans and bignumbers', function() { @@ -108,27 +107,123 @@ describe('subtract', function() { it('should throw an error when used with a string', function() { assert.throws(function () {subtract('hello ', 'world'); }); - assert.throws(function () {subtract('str', 123)}); - assert.throws(function () {subtract(123, 'str')}); + assert.throws(function () {subtract('str', 123);}); + assert.throws(function () {subtract(123, 'str');}); }); - it('should perform element-wise subtraction of two matrices', function() { - var a2 = math.matrix([[1,2],[3,4]]); - var a3 = math.matrix([[5,6],[7,8]]); - var a6 = subtract(a2, a3); - assert.ok(a6 instanceof math.type.Matrix); - assert.deepEqual(a6.size(), [2,2]); - assert.deepEqual(a6.valueOf(), [[-4,-4],[-4,-4]]); + describe('Array', function () { + + it('should subtract arrays correctly', function() { + var a2 = [[10,20],[30,40]]; + var a3 = [[5,6],[7,8]]; + var a4 = subtract(a2, a3); + assert.deepEqual(a4, [[5,14],[23,32]]); + }); + + it('should subtract a scalar and an array correctly', function() { + assert.deepEqual(subtract(2, [3,4]), [-1,-2]); + assert.deepEqual(subtract(2, [3,0]), [-1,2]); + assert.deepEqual(subtract([3,4], 2), [1,2]); + assert.deepEqual(subtract([3,0], 2), [1,-2]); + }); + + it('should subtract array and dense matrix correctly', function() { + var a = [1,2,3]; + var b = math.matrix([3,2,1]); + var c = subtract(a, b); + + assert.ok(c instanceof math.type.Matrix); + assert.deepEqual(c, math.matrix([-2,0,2])); + }); + + it('should subtract array and dense matrix correctly', function() { + var a = [[1,2,3],[4,5,6]]; + var b = math.sparse([[6,5,4],[ 3, 2, 1]]); + var c = subtract(a, b); + + assert.ok(c instanceof math.type.Matrix); + assert.deepEqual(c, math.matrix([[-5,-3,-1],[1,3,5]])); + }); + }); + + describe('DenseMatrix', function () { + + it('should subtract matrices correctly', function() { + var a2 = math.matrix([[10,20],[30,40]]); + var a3 = math.matrix([[5,6],[7,8]]); + var a4 = subtract(a2, a3); + assert.ok(a4 instanceof math.type.Matrix); + assert.deepEqual(a4.size(), [2,2]); + assert.deepEqual(a4.valueOf(), [[5,14],[23,32]]); + }); + + it('should subtract a scalar and a matrix correctly', function() { + assert.deepEqual(subtract(2, math.matrix([3,4])), math.matrix([-1,-2])); + assert.deepEqual(subtract(math.matrix([3,4]), 2), math.matrix([1,2])); + }); + + it('should subtract matrix and array correctly', function() { + var a = math.matrix([1,2,3]); + var b = [3,2,1]; + var c = subtract(a, b); + + assert.ok(c instanceof math.type.Matrix); + assert.deepEqual(c, math.matrix([-2,0,2])); + }); + + it('should subtract dense and sparse matrices correctly', function() { + var a = math.matrix([[1,2,3],[1,0,0]]); + var b = math.sparse([[3,2,1],[0,0,1]]); + var c = subtract(a, b); + + assert.ok(c instanceof math.type.Matrix); + assert.deepEqual(c, math.matrix([[-2,0,2],[1,0,-1]])); + }); + }); + + describe('SparseMatrix', function () { + + it('should subtract matrices correctly', function() { + var a2 = math.matrix([[10,20],[30,0]], 'sparse'); + var a3 = math.matrix([[5,6],[30,8]], 'sparse'); + var a4 = subtract(a2, a3); + assert.ok(a4 instanceof math.type.Matrix); + assert.deepEqual(a4, math.sparse([[5,14],[0,-8]])); + }); + + it('should subtract a scalar and a matrix correctly', function() { + assert.deepEqual(subtract(2, math.matrix([[3,4],[5,6]], 'sparse')).valueOf(), [[-1,-2],[-3,-4]]); + assert.deepEqual(subtract(2, math.matrix([[3,4],[0,6]], 'sparse')).valueOf(), [[-1,-2],[2,-4]]); + assert.deepEqual(subtract(math.matrix([[3,4],[5,6]], 'sparse'), 2).valueOf(), [[1,2],[3,4]]); + assert.deepEqual(subtract(math.matrix([[3,4],[0,6]], 'sparse'), 2).valueOf(), [[1,2],[-2,4]]); + }); + + it('should subtract matrix and array correctly', function() { + var a = math.matrix([[1,2,3],[1,0,0]], 'sparse'); + var b = [[3,2,1],[0,0,1]]; + var c = subtract(a, b); + + assert.ok(c instanceof math.type.Matrix); + assert.deepEqual(c.valueOf(), [[-2,0,2],[1,0,-1]]); + }); + + it('should subtract sparse and dense matrices correctly', function() { + var a = math.sparse([[1,2,3],[1,0,0]]); + var b = math.matrix([[3,2,1],[0,0,1]]); + var c = subtract(a, b); + + assert.ok(c instanceof math.type.Matrix); + assert.deepEqual(c, math.matrix([[-2,0,2],[1,0,-1]])); + }); }); it('should throw an error in case of invalid number of arguments', function() { - assert.throws(function () {subtract(1)}, /TypeError: Too few arguments/); - assert.throws(function () {subtract(1, 2, 3)}, /TypeError: Too many arguments/); + assert.throws(function () {subtract(1);}, /TypeError: Too few arguments/); + assert.throws(function () {subtract(1, 2, 3);}, /TypeError: Too many arguments/); }); it('should LaTeX subtract', function () { var expression = math.parse('subtract(2,1)'); assert.equal(expression.toTex(), '\\left(2-1\\right)'); }); - }); diff --git a/test/function/bitwise/bitAnd.test.js b/test/function/bitwise/bitAnd.test.js index 4b2d1a026..2900eb29b 100644 --- a/test/function/bitwise/bitAnd.test.js +++ b/test/function/bitwise/bitAnd.test.js @@ -58,9 +58,9 @@ describe('bitAnd', function () { }); it('should throw an error if used with a unit', function() { - assert.throws(function () {bitAnd(math.unit('5cm'), 2)}, /TypeError: Unexpected type of argument/); - assert.throws(function () {bitAnd(2, math.unit('5cm'))}, /TypeError: Unexpected type of argument/); - assert.throws(function () {bitAnd(math.unit('2cm'), math.unit('5cm'))}, /TypeError: Unexpected type of argument/); + assert.throws(function () {bitAnd(math.unit('5cm'), 2);}, /TypeError: Unexpected type of argument/); + assert.throws(function () {bitAnd(2, math.unit('5cm'));}, /TypeError: Unexpected type of argument/); + assert.throws(function () {bitAnd(math.unit('2cm'), math.unit('5cm'));}, /TypeError: Unexpected type of argument/); }); it('should throw an error if the parameters are not integers', function () { @@ -87,6 +87,88 @@ describe('bitAnd', function () { }, /Integers expected in function bitAnd/); }); + it('should bitwise and arrays correctly', function () { + var a = [[1,4],[3,2]]; + + // array - array + var b = [[5,8],[7,6]]; + var c = bitAnd(a, b); + assert.deepEqual(c, [[1,0],[3,2]]); + + // array - dense + b = math.matrix([[5,8],[7,6]]); + c = bitAnd(a, b); + assert.deepEqual(c, math.matrix([[1,0],[3,2]])); + + // array - sparse + b = math.sparse([[5,8],[7,6]]); + c = bitAnd(a, b); + assert.deepEqual(c, math.sparse([[1,0],[3,2]])); + }); + + it('should bitwise and dense matrix correctly', function () { + var a = math.matrix([[1,4],[3,2]]); + + // dense - array + var b = [[5,8],[7,6]]; + var c = bitAnd(a, b); + assert.deepEqual(c, math.matrix([[1,0],[3,2]])); + + // dense - dense + b = math.matrix([[5,8],[7,6]]); + c = bitAnd(a, b); + assert.deepEqual(c, math.matrix([[1,0],[3,2]])); + + // dense - sparse + b = math.sparse([[5,8],[7,6]]); + c = bitAnd(a, b); + assert.deepEqual(c, math.sparse([[1,0],[3,2]])); + }); + + it('should bitwise and sparse matrix correctly', function () { + var a = math.sparse([[1,4],[3,2]]); + + // sparse - array + var b = [[5,8],[7,6]]; + var c = bitAnd(a, b); + assert.deepEqual(c, math.sparse([[1,0],[3,2]])); + + // sparse - dense + b = math.matrix([[5,8],[7,6]]); + c = bitAnd(a, b); + assert.deepEqual(c, math.sparse([[1,0],[3,2]])); + + // sparse - sparse + b = math.sparse([[5,8],[7,6]]); + c = bitAnd(a, b); + assert.deepEqual(c, math.sparse([[1,0],[3,2]])); + + // sparse - sparse pattern + b = new math.type.SparseMatrix({ + index: [ 0, 1], + ptr: [ 0, 1, 2 ], + size: [ 2, 2 ] + }); + c = bitAnd(a, b); + assert.deepEqual( + c, + new math.type.SparseMatrix({ + index: [ 0, 1], + ptr: [ 0, 1, 2 ], + size: [ 2, 2 ] + })); + + // sparse pattern - sparse + c = bitAnd(b, a); + assert.deepEqual( + c, + new math.type.SparseMatrix({ + index: [ 0, 1], + ptr: [ 0, 1, 2 ], + size: [ 2, 2 ] + })); + }); + it('should bitwise and matrices correctly', function () { var a2 = math.matrix([[1,2],[3,4]]); var a3 = math.matrix([[5,6],[7,8]]); @@ -120,17 +202,17 @@ describe('bitAnd', function () { }); it('should throw an error in case of invalid number of arguments', function () { - assert.throws(function () {bitAnd(1)}, /TypeError: Too few arguments/); - assert.throws(function () {bitAnd(1, 2, 3)}, /TypeError: Too many arguments/); + assert.throws(function () {bitAnd(1);}, /TypeError: Too few arguments/); + assert.throws(function () {bitAnd(1, 2, 3);}, /TypeError: Too many arguments/); }); it('should throw an error in case of invalid type of arguments', function () { - assert.throws(function () {bitAnd(new Date(), true)}, /TypeError: Unexpected type of argument/); - assert.throws(function () {bitAnd(true, new Date())}, /TypeError: Unexpected type of argument/); - assert.throws(function () {bitAnd(true, 'foo')}, /TypeError: Unexpected type of argument/); - assert.throws(function () {bitAnd('foo', true)}, /TypeError: Unexpected type of argument/); - assert.throws(function () {bitAnd(true, undefined)}, /TypeError: Unexpected type of argument/); - assert.throws(function () {bitAnd(undefined, true)}, /TypeError: Unexpected type of argument/); + assert.throws(function () {bitAnd(new Date(), true);}, /TypeError: Unexpected type of argument/); + assert.throws(function () {bitAnd(true, new Date());}, /TypeError: Unexpected type of argument/); + assert.throws(function () {bitAnd(true, 'foo');}, /TypeError: Unexpected type of argument/); + assert.throws(function () {bitAnd('foo', true);}, /TypeError: Unexpected type of argument/); + assert.throws(function () {bitAnd(true, undefined);}, /TypeError: Unexpected type of argument/); + assert.throws(function () {bitAnd(undefined, true);}, /TypeError: Unexpected type of argument/); }); it('should LaTeX bitAnd', function () { diff --git a/test/function/bitwise/bitOr.test.js b/test/function/bitwise/bitOr.test.js index 2b91bc106..4b7b1c2d1 100644 --- a/test/function/bitwise/bitOr.test.js +++ b/test/function/bitwise/bitOr.test.js @@ -57,9 +57,9 @@ describe('bitOr', function () { }); it('should throw an error if used with a unit', function() { - assert.throws(function () {bitOr(math.unit('5cm'), 2)}, /TypeError: Unexpected type of argument/); - assert.throws(function () {bitOr(2, math.unit('5cm'))}, /TypeError: Unexpected type of argument/); - assert.throws(function () {bitOr(math.unit('2cm'), math.unit('5cm'))}, /TypeError: Unexpected type of argument/); + assert.throws(function () {bitOr(math.unit('5cm'), 2);}, /TypeError: Unexpected type of argument/); + assert.throws(function () {bitOr(2, math.unit('5cm'));}, /TypeError: Unexpected type of argument/); + assert.throws(function () {bitOr(math.unit('2cm'), math.unit('5cm'));}, /TypeError: Unexpected type of argument/); }); it('should throw an error if the parameters are not integers', function () { @@ -86,6 +86,89 @@ describe('bitOr', function () { }, /Integers expected in function bitOr/); }); + it('should bitwise or arrays correctly', function () { + var a = [[1,4],[3,2]]; + + // array - array + var b = [[5,8],[7,6]]; + var c = bitOr(a, b); + assert.deepEqual(c, [[5,12],[7,6]]); + + // array - dense + b = math.matrix([[5,8],[7,6]]); + c = bitOr(a, b); + assert.deepEqual(c, math.matrix([[5,12],[7,6]])); + + // array - sparse + b = math.sparse([[5,8],[7,6]]); + c = bitOr(a, b); + assert.deepEqual(c, math.matrix([[5,12],[7,6]])); + }); + + it('should bitwise or dense matrix correctly', function () { + var a = math.matrix([[1,4],[3,2]]); + + // dense - array + var b = [[5,8],[7,6]]; + var c = bitOr(a, b); + assert.deepEqual(c, math.matrix([[5,12],[7,6]])); + + // dense - dense + b = math.matrix([[5,8],[7,6]]); + c = bitOr(a, b); + assert.deepEqual(c, math.matrix([[5,12],[7,6]])); + + // dense - sparse + b = math.sparse([[5,8],[7,6]]); + c = bitOr(a, b); + assert.deepEqual(c, math.matrix([[5,12],[7,6]])); + }); + + it('should bitwise or sparse matrix correctly', function () { + var a = math.sparse([[1,4],[3,2]]); + + // sparse - array + var b = [[5,8],[7,6]]; + var c = bitOr(a, b); + assert.deepEqual(c, math.matrix([[5,12],[7,6]])); + + // sparse - dense + b = math.matrix([[5,8],[7,6]]); + c = bitOr(a, b); + assert.deepEqual(c, math.matrix([[5,12],[7,6]])); + + // sparse - sparse + b = math.sparse([[5,8],[7,6]]); + c = bitOr(a, b); + assert.deepEqual(c, math.sparse([[5,12],[7,6]])); + + // sparse - sparse pattern + a = math.sparse([[1,1],[0,0]]); + b = new math.type.SparseMatrix({ + index: [ 0, 1], + ptr: [ 0, 1, 2 ], + size: [ 2, 2 ] + }); + c = bitOr(a, b); + assert.deepEqual( + c, + new math.type.SparseMatrix({ + index: [0, 0, 1], + ptr: [0, 1, 3], + size: [2, 2] + })); + + // sparse pattern - sparse + c = bitOr(b, a); + assert.deepEqual( + c, + new math.type.SparseMatrix({ + index: [0, 1, 0], // row index not in order, not a problem! + ptr: [0, 1, 3], + size: [2, 2] + })); + }); + it('should bitwise or matrices correctly', function () { var a2 = math.matrix([[1,2],[3,4]]); var a3 = math.matrix([[5,6],[7,8]]); @@ -119,21 +202,21 @@ describe('bitOr', function () { }); it('should throw an error in case of invalid number of arguments', function () { - assert.throws(function () {bitOr(1)}, /TypeError: Too few arguments/); - assert.throws(function () {bitOr(1, 2, 3)}, /TypeError: Too many arguments/); + assert.throws(function () {bitOr(1);}, /TypeError: Too few arguments/); + assert.throws(function () {bitOr(1, 2, 3);}, /TypeError: Too many arguments/); }); + it('should throw an error in case of invalid type of arguments', function () { - assert.throws(function () {bitOr(new Date(), true)}, /TypeError: Unexpected type of argument/); - assert.throws(function () {bitOr(true, new Date())}, /TypeError: Unexpected type of argument/); - assert.throws(function () {bitOr(true, 'foo')}, /TypeError: Unexpected type of argument/); - assert.throws(function () {bitOr('foo', true)}, /TypeError: Unexpected type of argument/); - assert.throws(function () {bitOr(true, undefined)}, /TypeError: Unexpected type of argument/); - assert.throws(function () {bitOr(undefined, true)}, /TypeError: Unexpected type of argument/); + assert.throws(function () {bitOr(new Date(), true);}, /TypeError: Unexpected type of argument/); + assert.throws(function () {bitOr(true, new Date());}, /TypeError: Unexpected type of argument/); + assert.throws(function () {bitOr(true, 'foo');}, /TypeError: Unexpected type of argument/); + assert.throws(function () {bitOr('foo', true);}, /TypeError: Unexpected type of argument/); + assert.throws(function () {bitOr(true, undefined);}, /TypeError: Unexpected type of argument/); + assert.throws(function () {bitOr(undefined, true);}, /TypeError: Unexpected type of argument/); }); it('should LaTeX bitOr', function () { var expression = math.parse('bitOr(2,3)'); assert.equal(expression.toTex(), '\\left(2|3\\right)'); }); - }); diff --git a/test/function/bitwise/bitXor.test.js b/test/function/bitwise/bitXor.test.js index b4d6249e8..b43d41c06 100644 --- a/test/function/bitwise/bitXor.test.js +++ b/test/function/bitwise/bitXor.test.js @@ -1,6 +1,8 @@ // test bitXor var assert = require('assert'), math = require('../../../index'), + matrix = math.matrix, + sparse = math.sparse, bignumber = math.bignumber, bitXor = math.bitXor; @@ -59,9 +61,9 @@ describe('bitXor', function () { }); it('should throw an error if used with a unit', function() { - assert.throws(function () {bitXor(math.unit('5cm'), 2)}, /TypeError: Unexpected type of argument/); - assert.throws(function () {bitXor(2, math.unit('5cm'))}, /TypeError: Unexpected type of argument/); - assert.throws(function () {bitXor(math.unit('2cm'), math.unit('5cm'))}, /TypeError: Unexpected type of argument/); + assert.throws(function () {bitXor(math.unit('5cm'), 2);}, /TypeError: Unexpected type of argument/); + assert.throws(function () {bitXor(2, math.unit('5cm'));}, /TypeError: Unexpected type of argument/); + assert.throws(function () {bitXor(math.unit('2cm'), math.unit('5cm'));}, /TypeError: Unexpected type of argument/); }); it('should throw an error if the parameters are not integers', function () { @@ -88,54 +90,82 @@ describe('bitXor', function () { }, /Integers expected in function bitXor/); }); - it('should xor matrices correctly', function () { - var a2 = math.matrix([[1,2],[3,4]]); - var a3 = math.matrix([[5,6],[7,8]]); - var a4 = bitXor(a2, a3); - assert.ok(a4 instanceof math.type.Matrix); - assert.deepEqual(a4.size(), [2,2]); - assert.deepEqual(a4.valueOf(), [[4,4],[4,12]]); - var a5 = math.pow(a2, 2); - assert.ok(a5 instanceof math.type.Matrix); - assert.deepEqual(a5.size(), [2,2]); - assert.deepEqual(a5.valueOf(), [[7,10],[15,22]]); + describe('Array', function () { + + it('should bitwise xor array - scalar', function () { + assert.deepEqual(bitXor(12, [3, 9]), [15, 5]); + assert.deepEqual(bitXor([3, 9], 12), [15, 5]); + }); + + it('should bitwise xor array - array', function () { + assert.deepEqual(bitXor([[1, 2], [3, 4]], [[5, 6], [7, 8]]), [[4, 4],[4, 12]]); + }); + + it('should bitwise xor array - dense matrix', function () { + assert.deepEqual(bitXor([[1, 2], [3, 4]], matrix([[5, 6], [7, 8]])), matrix([[4, 4],[4, 12]])); + }); + + it('should bitwise xor array - sparse matrix', function () { + assert.deepEqual(bitXor([[1, 2], [3, 4]], sparse([[5, 6], [7, 8]])), matrix([[4, 4],[4, 12]])); + }); }); + + describe('DenseMatrix', function () { - it('should xor a scalar and a matrix correctly', function () { - assert.deepEqual(bitXor(12, math.matrix([3,9])), math.matrix([15,5])); - assert.deepEqual(bitXor(math.matrix([3,9]), 12), math.matrix([15,5])); + it('should bitwise xor dense matrix - scalar', function () { + assert.deepEqual(bitXor(12, matrix([3, 9])), matrix([15, 5])); + assert.deepEqual(bitXor(matrix([3, 9]), 12), matrix([15, 5])); + }); + + it('should bitwise xor dense matrix - array', function () { + assert.deepEqual(bitXor(matrix([[1, 2], [3, 4]]), [[5, 6], [7, 8]]), matrix([[4, 4],[4, 12]])); + }); + + it('should bitwise xor dense matrix - dense matrix', function () { + assert.deepEqual(bitXor(matrix([[1, 2], [3, 4]]), matrix([[5, 6], [7, 8]])), matrix([[4, 4],[4, 12]])); + }); + + it('should bitwise xor dense matrix - sparse matrix', function () { + assert.deepEqual(bitXor(matrix([[1, 2], [3, 4]]), sparse([[5, 6], [7, 8]])), matrix([[4, 4],[4, 12]])); + }); }); + + describe('SparseMatrix', function () { - it('should xor a scalar and an array correctly', function () { - assert.deepEqual(bitXor(12, [3,9]), [15,5]); - assert.deepEqual(bitXor([3,9], 12), [15,5]); - }); + it('should bitwise xor sparse matrix - scalar', function () { + assert.deepEqual(bitXor(12, sparse([[3, 9], [9, 3]])), matrix([[15, 5], [5, 15]])); + assert.deepEqual(bitXor(sparse([[3, 9], [9, 3]]), 12), matrix([[15, 5], [5, 15]])); + }); - it('should xor a matrix and an array correctly', function () { - var a = [6,4,28]; - var b = math.matrix([13,92,101]); - var c = bitXor(a, b); + it('should bitwise xor sparse matrix - array', function () { + assert.deepEqual(bitXor(sparse([[1, 2], [3, 4]]), [[5, 6], [7, 8]]), matrix([[4, 4],[4, 12]])); + }); - assert.ok(c instanceof math.type.Matrix); - assert.deepEqual(c, math.matrix([11,88,121])); + it('should bitwise xor sparse matrix - dense matrix', function () { + assert.deepEqual(bitXor(sparse([[1, 2], [3, 4]]), matrix([[5, 6], [7, 8]])), matrix([[4, 4],[4, 12]])); + }); + + it('should bitwise xor sparse matrix - sparse matrix', function () { + assert.deepEqual(bitXor(sparse([[1, 2], [3, 4]]), sparse([[5, 6], [7, 8]])), matrix([[4, 4],[4, 12]])); + }); }); it('should throw an error in case of invalid number of arguments', function () { - assert.throws(function () {bitXor(1)}, /TypeError: Too few arguments/); - assert.throws(function () {bitXor(1, 2, 3)}, /TypeError: Too many arguments/); + assert.throws(function () {bitXor(1);}, /TypeError: Too few arguments/); + assert.throws(function () {bitXor(1, 2, 3);}, /TypeError: Too many arguments/); }); + it('should throw an error in case of invalid type of arguments', function () { - assert.throws(function () {bitXor(new Date(), true)}, /TypeError: Unexpected type of argument/); - assert.throws(function () {bitXor(true, new Date())}, /TypeError: Unexpected type of argument/); - assert.throws(function () {bitXor(true, 'foo')}, /TypeError: Unexpected type of argument/); - assert.throws(function () {bitXor('foo', true)}, /TypeError: Unexpected type of argument/); - assert.throws(function () {bitXor(true, undefined)}, /TypeError: Unexpected type of argument/); - assert.throws(function () {bitXor(undefined, true)}, /TypeError: Unexpected type of argument/); + assert.throws(function () {bitXor(new Date(), true);}, /TypeError: Unexpected type of argument/); + assert.throws(function () {bitXor(true, new Date());}, /TypeError: Unexpected type of argument/); + assert.throws(function () {bitXor(true, 'foo');}, /TypeError: Unexpected type of argument/); + assert.throws(function () {bitXor('foo', true);}, /TypeError: Unexpected type of argument/); + assert.throws(function () {bitXor(true, undefined);}, /TypeError: Unexpected type of argument/); + assert.throws(function () {bitXor(undefined, true);}, /TypeError: Unexpected type of argument/); }); it('should LaTeX bitXor', function () { var expression = math.parse('bitXor(2,3)'); assert.equal(expression.toTex(), '\\left(2\\underline{|}3\\right)'); }); - }); diff --git a/test/function/bitwise/leftShift.test.js b/test/function/bitwise/leftShift.test.js index 64a4eb7f6..a15a9e9f5 100644 --- a/test/function/bitwise/leftShift.test.js +++ b/test/function/bitwise/leftShift.test.js @@ -1,7 +1,8 @@ // test leftShift var assert = require('assert'), - approx = require('../../../tools/approx'), math = require('../../../index'), + matrix = math.matrix, + sparse = math.sparse, bignumber = math.bignumber, leftShift = math.leftShift; @@ -64,9 +65,9 @@ describe('leftShift', function () { }); it('should throw an error if used with a unit', function() { - assert.throws(function () {leftShift(math.unit('5cm'), 2)}, /TypeError: Unexpected type of argument/); - assert.throws(function () {leftShift(2, math.unit('5cm'))}, /TypeError: Unexpected type of argument/); - assert.throws(function () {leftShift(math.unit('2cm'), math.unit('5cm'))}, /TypeError: Unexpected type of argument/); + assert.throws(function () {leftShift(math.unit('5cm'), 2);}, /TypeError: Unexpected type of argument/); + assert.throws(function () {leftShift(2, math.unit('5cm'));}, /TypeError: Unexpected type of argument/); + assert.throws(function () {leftShift(math.unit('2cm'), math.unit('5cm'));}, /TypeError: Unexpected type of argument/); }); it('should throw an error if the parameters are not integers', function () { @@ -93,43 +94,91 @@ describe('leftShift', function () { }, /Integers expected in function leftShift/); }); - it('should element-wise left shift a matrix', function () { - var a = math.matrix([1,2]); - var b = leftShift(a, 2); - assert.ok(b instanceof math.type.Matrix); - assert.deepEqual(b, math.matrix([4,8])); + describe('Array', function () { + + it('should left shift array and scalar', function () { + assert.deepEqual(leftShift([[1, 2], [8, 0]], 2), [[4, 8], [32, 0]]); + assert.deepEqual(leftShift(2, [[1, 2], [8, 0]]), [[4, 8], [512, 2]]); + }); + + it('should left shift array - array', function () { + assert.deepEqual(leftShift([[1, 2], [8, 0]], [[4, 8], [32, 0]]), [[16, 512], [8, 0]]); + assert.deepEqual(leftShift([[4, 8], [32, 0]], [[1, 2], [8, 0]]), [[8, 32], [8192, 0]]); + }); + + it('should left shift array - dense matrix', function () { + assert.deepEqual(leftShift([[1, 2], [8, 0]], matrix([[4, 8], [32, 0]])), matrix([[16, 512], [8, 0]])); + assert.deepEqual(leftShift([[4, 8], [32, 0]], matrix([[1, 2], [8, 0]])), matrix([[8, 32], [8192, 0]])); + }); - a = math.matrix([[1,2],[3,4]]); - b = leftShift(a, 2); - assert.ok(b instanceof math.type.Matrix); - assert.deepEqual(b, math.matrix([[4,8],[12,16]])); + it('should left shift array - sparse matrix', function () { + assert.deepEqual(leftShift([[1, 2], [8, 0]], sparse([[4, 8], [32, 0]])), matrix([[16, 512], [8, 0]])); + assert.deepEqual(leftShift([[4, 8], [32, 0]], sparse([[1, 2], [8, 0]])), matrix([[8, 32], [8192, 0]])); + }); + }); + + describe('DenseMatrix', function () { + + it('should left shift dense matrix and scalar', function () { + assert.deepEqual(leftShift(matrix([[1, 2], [8, 0]]), 2), matrix([[4, 8], [32, 0]])); + assert.deepEqual(leftShift(2, matrix([[1, 2], [8, 0]])), matrix([[4, 8], [512, 2]])); + }); + + it('should left shift dense matrix - array', function () { + assert.deepEqual(leftShift(matrix([[1, 2], [8, 0]]), [[4, 8], [32, 0]]), matrix([[16, 512], [8, 0]])); + assert.deepEqual(leftShift(matrix([[4, 8], [32, 0]]), [[1, 2], [8, 0]]), matrix([[8, 32], [8192, 0]])); + }); + + it('should left shift dense matrix - dense matrix', function () { + assert.deepEqual(leftShift(matrix([[1, 2], [8, 0]]), matrix([[4, 8], [32, 0]])), matrix([[16, 512], [8, 0]])); + assert.deepEqual(leftShift(matrix([[4, 8], [32, 0]]), matrix([[1, 2], [8, 0]])), matrix([[8, 32], [8192, 0]])); + }); + + it('should left shift dense matrix - sparse matrix', function () { + assert.deepEqual(leftShift(matrix([[1, 2], [8, 0]]), sparse([[4, 8], [32, 0]])), matrix([[16, 512], [8, 0]])); + assert.deepEqual(leftShift(matrix([[4, 8], [32, 0]]), sparse([[1, 2], [8, 0]])), matrix([[8, 32], [8192, 0]])); + }); }); - it('should element-wise left shift an array', function () { - var a = [[1,2],[3,4]]; - assert.deepEqual(leftShift(a[0], 0), a[0]); - assert.deepEqual(leftShift(a[0], 2), [4,8]); - assert.deepEqual(leftShift(a, 0), a); - assert.deepEqual(leftShift(a, 2), [[4,8],[12,16]]); + describe('SparseMatrix', function () { + + it('should left shift sparse matrix and scalar', function () { + assert.deepEqual(leftShift(sparse([[1, 2], [8, 0]]), 2), sparse([[4, 8], [32, 0]])); + assert.deepEqual(leftShift(2, sparse([[1, 2], [8, 0]])), matrix([[4, 8], [512, 2]])); + }); + + it('should left shift sparse matrix - array', function () { + assert.deepEqual(leftShift(sparse([[1, 2], [8, 0]]), [[4, 8], [32, 0]]), sparse([[16, 512], [8, 0]])); + assert.deepEqual(leftShift(sparse([[4, 8], [32, 0]]), [[1, 2], [8, 0]]), sparse([[8, 32], [8192, 0]])); + }); + + it('should left shift sparse matrix - dense matrix', function () { + assert.deepEqual(leftShift(sparse([[1, 2], [8, 0]]), matrix([[4, 8], [32, 0]])), sparse([[16, 512], [8, 0]])); + assert.deepEqual(leftShift(sparse([[4, 8], [32, 0]]), matrix([[1, 2], [8, 0]])), sparse([[8, 32], [8192, 0]])); + }); + + it('should left shift sparse matrix - sparse matrix', function () { + assert.deepEqual(leftShift(sparse([[1, 2], [8, 0]]), sparse([[4, 8], [32, 0]])), sparse([[16, 512], [8, 0]])); + assert.deepEqual(leftShift(sparse([[4, 8], [32, 0]]), sparse([[1, 2], [8, 0]])), sparse([[8, 32], [8192, 0]])); + }); }); it('should throw an error if used with wrong number of arguments', function () { - assert.throws(function () {leftShift(1)}, /TypeError: Too few arguments/); - assert.throws(function () {leftShift(1, 2, 3)}, /TypeError: Too many arguments/); + assert.throws(function () {leftShift(1);}, /TypeError: Too few arguments/); + assert.throws(function () {leftShift(1, 2, 3);}, /TypeError: Too many arguments/); }); it('should throw an error in case of invalid type of arguments', function () { - assert.throws(function () {leftShift(new Date(), true)}, /TypeError: Unexpected type of argument/); - assert.throws(function () {leftShift(true, new Date())}, /TypeError: Unexpected type of argument/); - assert.throws(function () {leftShift(true, 'foo')}, /TypeError: Unexpected type of argument/); - assert.throws(function () {leftShift('foo', true)}, /TypeError: Unexpected type of argument/); - assert.throws(function () {leftShift(true, undefined)}, /TypeError: Unexpected type of argument/); - assert.throws(function () {leftShift(undefined, true)}, /TypeError: Unexpected type of argument/); + assert.throws(function () {leftShift(new Date(), true);}, /TypeError: Unexpected type of argument/); + assert.throws(function () {leftShift(true, new Date());}, /TypeError: Unexpected type of argument/); + assert.throws(function () {leftShift(true, 'foo');}, /TypeError: Unexpected type of argument/); + assert.throws(function () {leftShift('foo', true);}, /TypeError: Unexpected type of argument/); + assert.throws(function () {leftShift(true, undefined);}, /TypeError: Unexpected type of argument/); + assert.throws(function () {leftShift(undefined, true);}, /TypeError: Unexpected type of argument/); }); it('should LaTeX leftShift', function () { var expression = math.parse('leftShift(2,3)'); assert.equal(expression.toTex(), '\\left(2<<3\\right)'); }); - }); diff --git a/test/function/bitwise/rightArithShift.test.js b/test/function/bitwise/rightArithShift.test.js index 6dc42bc30..91a57ba25 100644 --- a/test/function/bitwise/rightArithShift.test.js +++ b/test/function/bitwise/rightArithShift.test.js @@ -1,6 +1,8 @@ // test rightArithShift var assert = require('assert'), math = require('../../../index'), + matrix = math.matrix, + sparse = math.sparse, bignumber = math.bignumber, rightArithShift = math.rightArithShift; @@ -96,24 +98,73 @@ describe('rightArithShift', function () { assert.throws(function () {rightArithShift(math.unit('2cm'), math.unit('5cm'))}, /TypeError: Unexpected type of argument/); }); - it('should element-wise right arithmetically shift a matrix', function () { - var a = math.matrix([4,8]); - var b = rightArithShift(a, 2); - assert.ok(b instanceof math.type.Matrix); - assert.deepEqual(b, math.matrix([1,2])); - - a = math.matrix([[4,8],[12,16]]); - b = rightArithShift(a, 2); - assert.ok(b instanceof math.type.Matrix); - assert.deepEqual(b, math.matrix([[1,2],[3,4]])); + describe('Array', function () { + + it('should right arithmetically shift array - scalar', function () { + assert.deepEqual(rightArithShift([[1, 2], [8, 0]], 2), [[0, 0], [2, 0]]); + assert.deepEqual(rightArithShift(2, [[1, 2], [8, 0]]), [[1, 0], [0, 2]]); + }); + + it('should right arithmetically shift array - array', function () { + assert.deepEqual(rightArithShift([[1, 2], [8, 0]], [[4, 8], [32, 0]]), [[0, 0], [8, 0]]); + assert.deepEqual(rightArithShift([[4, 8], [32, 0]], [[1, 2], [8, 0]]), [[2, 2], [0, 0]]); + }); + + it('should right arithmetically shift array - dense matrix', function () { + assert.deepEqual(rightArithShift([[1, 2], [8, 0]], matrix([[4, 8], [32, 0]])), matrix([[0, 0], [8, 0]])); + assert.deepEqual(rightArithShift([[4, 8], [32, 0]], matrix([[1, 2], [8, 0]])), matrix([[2, 2], [0, 0]])); + }); + + it('should right arithmetically shift array - sparse matrix', function () { + assert.deepEqual(rightArithShift([[1, 2], [8, 0]], sparse([[4, 8], [32, 0]])), matrix([[0, 0], [8, 0]])); + assert.deepEqual(rightArithShift([[4, 8], [32, 0]], sparse([[1, 2], [8, 0]])), matrix([[2, 2], [0, 0]])); + }); }); - it('should element-wise right arithmetically shift an array', function () { - var a = [[4,8],[12,16]]; - assert.deepEqual(rightArithShift(a[0], 0), a[0]); - assert.deepEqual(rightArithShift(a[0], 2), [1,2]); - assert.deepEqual(rightArithShift(a, 0), a); - assert.deepEqual(rightArithShift(a, 2), [[1,2],[3,4]]); + describe('DenseMatrix', function () { + + it('should right arithmetically shift dense matrix - scalar', function () { + assert.deepEqual(rightArithShift(matrix([[1, 2], [8, 0]]), 2), matrix([[0, 0], [2, 0]])); + assert.deepEqual(rightArithShift(2, matrix([[1, 2], [8, 0]])), matrix([[1, 0], [0, 2]])); + }); + + it('should right arithmetically shift dense matrix - array', function () { + assert.deepEqual(rightArithShift(matrix([[1, 2], [8, 0]]), [[4, 8], [32, 0]]), matrix([[0, 0], [8, 0]])); + assert.deepEqual(rightArithShift(matrix([[4, 8], [32, 0]]), [[1, 2], [8, 0]]), matrix([[2, 2], [0, 0]])); + }); + + it('should right arithmetically shift dense matrix - dense matrix', function () { + assert.deepEqual(rightArithShift(matrix([[1, 2], [8, 0]]), matrix([[4, 8], [32, 0]])), matrix([[0, 0], [8, 0]])); + assert.deepEqual(rightArithShift(matrix([[4, 8], [32, 0]]), matrix([[1, 2], [8, 0]])), matrix([[2, 2], [0, 0]])); + }); + + it('should right arithmetically shift dense matrix - sparse matrix', function () { + assert.deepEqual(rightArithShift(matrix([[1, 2], [8, 0]]), sparse([[4, 8], [32, 0]])), matrix([[0, 0], [8, 0]])); + assert.deepEqual(rightArithShift(matrix([[4, 8], [32, 0]]), sparse([[1, 2], [8, 0]])), matrix([[2, 2], [0, 0]])); + }); + }); + + describe('SparseMatrix', function () { + + it('should right arithmetically shift sparse matrix - scalar', function () { + assert.deepEqual(rightArithShift(sparse([[1, 2], [8, 0]]), 2), sparse([[0, 0], [2, 0]])); + assert.deepEqual(rightArithShift(2, sparse([[1, 2], [8, 0]])), matrix([[1, 0], [0, 2]])); + }); + + it('should right arithmetically shift sparse matrix - array', function () { + assert.deepEqual(rightArithShift(sparse([[1, 2], [8, 0]]), [[4, 8], [32, 0]]), sparse([[0, 0], [8, 0]])); + assert.deepEqual(rightArithShift(sparse([[4, 8], [32, 0]]), [[1, 2], [8, 0]]), sparse([[2, 2], [0, 0]])); + }); + + it('should right arithmetically shift sparse matrix - dense matrix', function () { + assert.deepEqual(rightArithShift(sparse([[1, 2], [8, 0]]), matrix([[4, 8], [32, 0]])), sparse([[0, 0], [8, 0]])); + assert.deepEqual(rightArithShift(sparse([[4, 8], [32, 0]]), matrix([[1, 2], [8, 0]])), sparse([[2, 2], [0, 0]])); + }); + + it('should right arithmetically shift sparse matrix - sparse matrix', function () { + assert.deepEqual(rightArithShift(sparse([[1, 2], [8, 0]]), sparse([[4, 8], [32, 0]])), sparse([[0, 0], [8, 0]])); + assert.deepEqual(rightArithShift(sparse([[4, 8], [32, 0]]), sparse([[1, 2], [8, 0]])), sparse([[2, 2], [0, 0]])); + }); }); it('should throw an error if used with wrong number of arguments', function () { @@ -134,5 +185,4 @@ describe('rightArithShift', function () { var expression = math.parse('rightArithShift(3,2)'); assert.equal(expression.toTex(), '\\left(3>>2\\right)'); }); - }); diff --git a/test/function/bitwise/rightLogShift.test.js b/test/function/bitwise/rightLogShift.test.js index 58c00f486..3c396fb5a 100644 --- a/test/function/bitwise/rightLogShift.test.js +++ b/test/function/bitwise/rightLogShift.test.js @@ -1,6 +1,8 @@ // test rightLogShift var assert = require('assert'), math = require('../../../index'), + matrix = math.matrix, + sparse = math.sparse, rightLogShift = math.rightLogShift; describe('rightLogShift', function () { @@ -50,43 +52,95 @@ describe('rightLogShift', function () { }); it('should throw an error if used with a unit', function() { - assert.throws(function () {rightLogShift(math.unit('5cm'), 2)}, /TypeError: Unexpected type of argument/); - assert.throws(function () {rightLogShift(2, math.unit('5cm'))}, /TypeError: Unexpected type of argument/); - assert.throws(function () {rightLogShift(math.unit('2cm'), math.unit('5cm'))}, /TypeError: Unexpected type of argument/); + assert.throws(function () {rightLogShift(math.unit('5cm'), 2);}, /TypeError: Unexpected type of argument/); + assert.throws(function () {rightLogShift(2, math.unit('5cm'));}, /TypeError: Unexpected type of argument/); + assert.throws(function () {rightLogShift(math.unit('2cm'), math.unit('5cm'));}, /TypeError: Unexpected type of argument/); }); - it('should element-wise right logically shift a matrix', function () { - var a = math.matrix([4,8]); - var b = rightLogShift(a, 2); - assert.ok(b instanceof math.type.Matrix); - assert.deepEqual(b, math.matrix([1,2])); + describe('Array', function () { - a = math.matrix([[4,8],[12,16]]); - b = rightLogShift(a, 2); - assert.ok(b instanceof math.type.Matrix); - assert.deepEqual(b, math.matrix([[1,2],[3,4]])); + it('should right arithmetically shift array - scalar', function () { + assert.deepEqual(rightLogShift([[4, 8], [8, 0]], 2), [[1, 2], [2, 0]]); + assert.deepEqual(rightLogShift([[4, 8], [12, 16]], 2), [[1, 2], [3, 4]]); + assert.deepEqual(rightLogShift(2, [[1, 2], [8, 0]]), [[1, 0], [0, 2]]); + }); + + it('should right arithmetically shift array - array', function () { + assert.deepEqual(rightLogShift([[1, 2], [8, 0]], [[4, 8], [32, 0]]), [[0, 0], [8, 0]]); + assert.deepEqual(rightLogShift([[4, 8], [32, 0]], [[1, 2], [8, 0]]), [[2, 2], [0, 0]]); + }); + + it('should right arithmetically shift array - dense matrix', function () { + assert.deepEqual(rightLogShift([[1, 2], [8, 0]], matrix([[4, 8], [32, 0]])), matrix([[0, 0], [8, 0]])); + assert.deepEqual(rightLogShift([[4, 8], [32, 0]], matrix([[1, 2], [8, 0]])), matrix([[2, 2], [0, 0]])); + }); + + it('should right arithmetically shift array - sparse matrix', function () { + assert.deepEqual(rightLogShift([[1, 2], [8, 0]], sparse([[4, 8], [32, 0]])), matrix([[0, 0], [8, 0]])); + assert.deepEqual(rightLogShift([[4, 8], [32, 0]], sparse([[1, 2], [8, 0]])), matrix([[2, 2], [0, 0]])); + }); + }); + + describe('DenseMatrix', function () { + + it('should right arithmetically shift dense matrix - scalar', function () { + assert.deepEqual(rightLogShift(matrix([[4, 8], [8, 0]]), 2), matrix([[1, 2], [2, 0]])); + assert.deepEqual(rightLogShift(matrix([[4, 8], [12, 16]]), 2), matrix([[1, 2], [3, 4]])); + assert.deepEqual(rightLogShift(2, matrix([[1, 2], [8, 0]])), matrix([[1, 0], [0, 2]])); + }); + + it('should right arithmetically shift dense matrix - array', function () { + assert.deepEqual(rightLogShift(matrix([[1, 2], [8, 0]]), [[4, 8], [32, 0]]), matrix([[0, 0], [8, 0]])); + assert.deepEqual(rightLogShift(matrix([[4, 8], [32, 0]]), [[1, 2], [8, 0]]), matrix([[2, 2], [0, 0]])); + }); + + it('should right arithmetically shift dense matrix - dense matrix', function () { + assert.deepEqual(rightLogShift(matrix([[1, 2], [8, 0]]), matrix([[4, 8], [32, 0]])), matrix([[0, 0], [8, 0]])); + assert.deepEqual(rightLogShift(matrix([[4, 8], [32, 0]]), matrix([[1, 2], [8, 0]])), matrix([[2, 2], [0, 0]])); + }); + + it('should right arithmetically shift dense matrix - sparse matrix', function () { + assert.deepEqual(rightLogShift(matrix([[1, 2], [8, 0]]), sparse([[4, 8], [32, 0]])), matrix([[0, 0], [8, 0]])); + assert.deepEqual(rightLogShift(matrix([[4, 8], [32, 0]]), sparse([[1, 2], [8, 0]])), matrix([[2, 2], [0, 0]])); + }); }); - it('should element-wise right logically shift an array', function () { - var a = [[4,8],[12,16]]; - assert.deepEqual(rightLogShift(a[0], 0), a[0]); - assert.deepEqual(rightLogShift(a[0], 2), [1,2]); - assert.deepEqual(rightLogShift(a, 0), a); - assert.deepEqual(rightLogShift(a, 2), [[1,2],[3,4]]); + describe('SparseMatrix', function () { + + it('should right arithmetically shift sparse matrix - scalar', function () { + assert.deepEqual(rightLogShift(sparse([[4, 8], [8, 0]]), 2), sparse([[1, 2], [2, 0]])); + assert.deepEqual(rightLogShift(sparse([[4, 8], [12, 16]]), 2), sparse([[1, 2], [3, 4]])); + assert.deepEqual(rightLogShift(2, sparse([[1, 2], [8, 0]])), matrix([[1, 0], [0, 2]])); + }); + + it('should right arithmetically shift sparse matrix - array', function () { + assert.deepEqual(rightLogShift(sparse([[1, 2], [8, 0]]), [[4, 8], [32, 0]]), sparse([[0, 0], [8, 0]])); + assert.deepEqual(rightLogShift(sparse([[4, 8], [32, 0]]), [[1, 2], [8, 0]]), sparse([[2, 2], [0, 0]])); + }); + + it('should right arithmetically shift sparse matrix - dense matrix', function () { + assert.deepEqual(rightLogShift(sparse([[1, 2], [8, 0]]), matrix([[4, 8], [32, 0]])), sparse([[0, 0], [8, 0]])); + assert.deepEqual(rightLogShift(sparse([[4, 8], [32, 0]]), matrix([[1, 2], [8, 0]])), sparse([[2, 2], [0, 0]])); + }); + + it('should right arithmetically shift sparse matrix - sparse matrix', function () { + assert.deepEqual(rightLogShift(sparse([[1, 2], [8, 0]]), sparse([[4, 8], [32, 0]])), sparse([[0, 0], [8, 0]])); + assert.deepEqual(rightLogShift(sparse([[4, 8], [32, 0]]), sparse([[1, 2], [8, 0]])), sparse([[2, 2], [0, 0]])); + }); }); it('should throw an error if used with wrong number of arguments', function () { - assert.throws(function () {rightLogShift(1)}, /TypeError: Too few arguments/); - assert.throws(function () {rightLogShift(1, 2, 3)}, /TypeError: Too many arguments/); + assert.throws(function () {rightLogShift(1);}, /TypeError: Too few arguments/); + assert.throws(function () {rightLogShift(1, 2, 3);}, /TypeError: Too many arguments/); }); it('should throw an error in case of invalid type of arguments', function () { - assert.throws(function () {rightLogShift(new Date(), true)}, /TypeError: Unexpected type of argument/); - assert.throws(function () {rightLogShift(true, new Date())}, /TypeError: Unexpected type of argument/); - assert.throws(function () {rightLogShift(true, 'foo')}, /TypeError: Unexpected type of argument/); - assert.throws(function () {rightLogShift('foo', true)}, /TypeError: Unexpected type of argument/); - assert.throws(function () {rightLogShift(true, undefined)}, /TypeError: Unexpected type of argument/); - assert.throws(function () {rightLogShift(undefined, true)}, /TypeError: Unexpected type of argument/); + assert.throws(function () {rightLogShift(new Date(), true);}, /TypeError: Unexpected type of argument/); + assert.throws(function () {rightLogShift(true, new Date());}, /TypeError: Unexpected type of argument/); + assert.throws(function () {rightLogShift(true, 'foo');}, /TypeError: Unexpected type of argument/); + assert.throws(function () {rightLogShift('foo', true);}, /TypeError: Unexpected type of argument/); + assert.throws(function () {rightLogShift(true, undefined);}, /TypeError: Unexpected type of argument/); + assert.throws(function () {rightLogShift(undefined, true);}, /TypeError: Unexpected type of argument/); }); it('should LaTeX rightLogShift', function () { diff --git a/test/function/construction/matrix.test.js b/test/function/construction/matrix.test.js index 66e5208cc..408b5d777 100644 --- a/test/function/construction/matrix.test.js +++ b/test/function/construction/matrix.test.js @@ -17,6 +17,13 @@ describe('matrix', function() { assert.deepEqual(math.size(a), matrix([0])); }); + it('should create empty matrix, dense format, number datatype', function() { + var a = matrix('dense', 'number'); + assert.ok(a instanceof math.type.Matrix); + assert.deepEqual(math.size(a), matrix([0])); + assert(a.datatype(), 'number'); + }); + it('should create empty matrix, sparse', function() { var a = matrix('sparse'); assert.ok(a instanceof math.type.Matrix); @@ -37,12 +44,30 @@ describe('matrix', function() { assert.deepEqual(math.size(c), matrix([2,2], 'dense')); }); + it('should be the identity if called with a matrix, dense format, number datatype', function() { + var b = matrix([[1,2],[3,4]], 'dense', 'number'); + var c = matrix(b, 'dense'); + assert.ok(c._data != b._data); // data should be cloned + assert.ok(c._size != b._size); + assert.deepEqual(c._data, b._data); + assert.deepEqual(c._size, b._size); + assert.ok(c.datatype() === 'number'); + }); + it('should be the identity if called with a matrix, sparse', function() { var b = matrix([[1,2],[3,4]], 'sparse'); var c = matrix(b, 'sparse'); assert.ok(c._values != b._values); // data should be cloned assert.deepEqual(c, matrix([[1,2],[3,4]], 'sparse')); }); + + it('should be the identity if called with a matrix, sparse, number datatype', function() { + var b = matrix([[1,2],[3,4]], 'sparse', 'number'); + var c = matrix(b, 'sparse'); + assert.ok(c._values != b._values); // data should be cloned + assert.deepEqual(c.valueOf(), b.valueOf()); + assert.ok(c.datatype() === 'number'); + }); it('should create a matrix from a range correctly', function() { var d = matrix(math.range(1,6)); @@ -60,7 +85,7 @@ describe('matrix', function() { }); it('should throw an error if called with too many arguments', function() { - assert.throws(function () {matrix([], 3, 3);}, /TypeError: Too many arguments/); + assert.throws(function () {matrix([], 3, 3, 7);}, /TypeError: Too many arguments/); }); it('should throw an error when called with an invalid storage format', function () { diff --git a/test/function/construction/sparse.test.js b/test/function/construction/sparse.test.js index aeacc15f8..931070ab2 100644 --- a/test/function/construction/sparse.test.js +++ b/test/function/construction/sparse.test.js @@ -10,6 +10,12 @@ describe('sparse', function() { assert.ok(a instanceof math.type.Matrix); }); + it('should create empty matrix, number datatype', function() { + var a = sparse('number'); + assert.ok(a instanceof math.type.Matrix); + assert.ok(a.datatype() === 'number'); + }); + it('should be the identity if called with a matrix', function() { var b = sparse([[1,2],[3,4]]); var c = sparse(b); @@ -17,6 +23,14 @@ describe('sparse', function() { assert.deepEqual(c, sparse([[1,2],[3,4]])); }); + it('should be the identity if called with a matrix, number datatype', function() { + var b = sparse([[1,2],[3,4]], 'number'); + var c = sparse(b); + assert.ok(c._values != b._values); // data should be cloned + assert.deepEqual(c.valueOf(), b.valueOf()); + assert.ok(c.datatype() === 'number'); + }); + it('should throw an error if called with an invalid argument', function() { assert.throws(function () { sparse(new Date()); }, TypeError); }); diff --git a/test/function/logical/and.test.js b/test/function/logical/and.test.js index 3be18b231..b017761e0 100644 --- a/test/function/logical/and.test.js +++ b/test/function/logical/and.test.js @@ -4,6 +4,7 @@ var assert = require('assert'), bignumber = math.bignumber, complex = math.complex, matrix = math.matrix, + sparse = math.sparse, unit = math.unit, and = math.and; @@ -107,43 +108,86 @@ describe('and', function () { assert.strictEqual(and(unit(0, 'km'), unit(100, 'gram')), false); }); - it('should and two arrays', function () { - assert.deepEqual(and([0, 1, 0, 12], [0, 0, 1, 22]), [false, false, false, true]); - assert.deepEqual(and([], []), []); + describe('Array', function () { + + it('should and array - scalar', function () { + assert.deepEqual(and(10, [0, 2]), [false, true]); + assert.deepEqual(and([0, 2], 10), [false, true]); + }); + + it('should and array - array', function () { + assert.deepEqual(and([0, 1, 0, 12], [0, 0, 1, 22]), [false, false, false, true]); + assert.deepEqual(and([], []), []); + }); + + it('should and array - dense matrix', function () { + assert.deepEqual(and([0, 1, 0, 12], matrix([0, 0, 1, 22])), matrix([false, false, false, true])); + assert.deepEqual(and([], matrix([])), matrix([])); + }); + + it('should and array - sparse matrix', function () { + assert.deepEqual(and([[0, 1], [0, 12]], sparse([[0, 0], [1, 22]])), sparse([[false, false], [false, true]])); + }); }); + + describe('DenseMatrix', function () { - it('should and mixed numbers and arrays', function () { - assert.deepEqual(and(10, [0, 2]), [false, true]); - assert.deepEqual(and([0, 2], 10), [false, true]); + it('should and dense matrix - scalar', function () { + assert.deepEqual(and(10, matrix([0, 2])), matrix([false, true])); + assert.deepEqual(and(matrix([0, 2]), 10), matrix([false, true])); + }); + + it('should and dense matrix - array', function () { + assert.deepEqual(and(matrix([0, 1, 0, 12]), [0, 0, 1, 22]), matrix([false, false, false, true])); + assert.deepEqual(and(matrix([]), []), matrix([])); + }); + + it('should and dense matrix - dense matrix', function () { + assert.deepEqual(and(matrix([0, 1, 0, 12]), matrix([0, 0, 1, 22])), matrix([false, false, false, true])); + assert.deepEqual(and(matrix([]), matrix([])), matrix([])); + }); + + it('should and dense matrix - sparse matrix', function () { + assert.deepEqual(and(matrix([[0, 1], [0, 12]]), sparse([[0, 0], [1, 22]])), sparse([[false, false], [false, true]])); + }); }); + + describe('SparseMatrix', function () { - it('should and two matrices', function () { - assert.deepEqual(and(matrix([0, 1, 0, 12]), matrix([0, 0, 1, 22])), matrix([false, false, false, true])); - assert.deepEqual(and(matrix([]), matrix([])), matrix([])); - }); + it('should and sparse matrix - scalar', function () { + assert.deepEqual(and(10, sparse([[0], [2]])), sparse([[false], [true]])); + assert.deepEqual(and(sparse([[0], [2]]), 10), sparse([[false], [true]])); + }); - it('should and mixed numbers and matrices', function () { - assert.deepEqual(and(10, matrix([0, 2])), matrix([false, true])); - assert.deepEqual(and(matrix([0, 2]), 10), matrix([false, true])); + it('should and sparse matrix - array', function () { + assert.deepEqual(and(sparse([[0, 1], [0, 12]]), [[0, 0], [1, 22]]), sparse([[false, false], [false, true]])); + }); + + it('should and sparse matrix - dense matrix', function () { + assert.deepEqual(and(sparse([[0, 1], [0, 12]]), matrix([[0, 0], [1, 22]])), sparse([[false, false], [false, true]])); + }); + + it('should and sparse matrix - sparse matrix', function () { + assert.deepEqual(and(sparse([[0, 1], [0, 12]]), sparse([[0, 0], [1, 22]])), sparse([[false, false], [false, true]])); + }); }); it('should throw an error in case of invalid number of arguments', function () { - assert.throws(function () {and(1)}, /TypeError: Too few arguments/); - assert.throws(function () {and(1, 2, 3)}, /TypeError: Too many arguments/); + assert.throws(function () {and(1);}, /TypeError: Too few arguments/); + assert.throws(function () {and(1, 2, 3);}, /TypeError: Too many arguments/); }); it('should throw an error in case of invalid type of arguments', function () { - assert.throws(function () {and(new Date(), true)}, /TypeError: Unexpected type of argument/); - assert.throws(function () {and(true, new Date())}, /TypeError: Unexpected type of argument/); - assert.throws(function () {and(true, 'foo')}, /TypeError: Unexpected type of argument/); - assert.throws(function () {and('foo', true)}, /TypeError: Unexpected type of argument/); - assert.throws(function () {and(true, undefined)}, /TypeError: Unexpected type of argument/); - assert.throws(function () {and(undefined, true)}, /TypeError: Unexpected type of argument/); + assert.throws(function () {and(new Date(), true);}, /TypeError: Unexpected type of argument/); + assert.throws(function () {and(true, new Date());}, /TypeError: Unexpected type of argument/); + assert.throws(function () {and(true, 'foo');}, /TypeError: Unexpected type of argument/); + assert.throws(function () {and('foo', true);}, /TypeError: Unexpected type of argument/); + assert.throws(function () {and(true, undefined);}, /TypeError: Unexpected type of argument/); + assert.throws(function () {and(undefined, true);}, /TypeError: Unexpected type of argument/); }); it('should LaTeX and', function () { var expression = math.parse('and(1,2)'); assert.equal(expression.toTex(), '\\left(1\\wedge2\\right)'); }); - }); diff --git a/test/function/logical/or.test.js b/test/function/logical/or.test.js index a46ea7c76..e1b723cc8 100644 --- a/test/function/logical/or.test.js +++ b/test/function/logical/or.test.js @@ -4,6 +4,7 @@ var assert = require('assert'), bignumber = math.bignumber, complex = math.complex, matrix = math.matrix, + sparse = math.sparse, unit = math.unit, or = math.or; @@ -138,35 +139,86 @@ describe('or', function () { assert.deepEqual(or([0, 2], 0), [false, true]); }); - it('should or two matrices', function () { - assert.deepEqual(or(matrix([0, 1, 0, 12]), matrix([0, 0, 1, 22])), matrix([false, true, true, true])); - assert.deepEqual(or(matrix([]), matrix([])), matrix([])); + describe('Array', function () { + + it('should or array - scalar', function () { + assert.deepEqual(or(10, [0, 2]), [true, true]); + assert.deepEqual(or([0, 2], 10), [true, true]); + }); + + it('should or array - array', function () { + assert.deepEqual(or([0, 1, 0, 12], [0, 0, 1, 22]), [false, true, true, true]); + assert.deepEqual(or([], []), []); + }); + + it('should or array - dense matrix', function () { + assert.deepEqual(or([0, 1, 0, 12], matrix([0, 0, 1, 22])), matrix([false, true, true, true])); + assert.deepEqual(or([], matrix([])), matrix([])); + }); + + it('should or array - sparse matrix', function () { + assert.deepEqual(or([[0, 1], [0, 12]], sparse([[0, 0], [1, 22]])), matrix([[false, true], [true, true]])); + }); }); - it('should or mixed numbers and matrices', function () { - assert.deepEqual(or(10, matrix([0, 2])), matrix([true, true])); - assert.deepEqual(or(matrix([0, 2]), 10), matrix([true, true])); - assert.deepEqual(or(0, matrix([0, 2])), matrix([false, true])); - assert.deepEqual(or(matrix([0, 2]), 0), matrix([false, true])); + describe('DenseMatrix', function () { + + it('should or dense matrix - scalar', function () { + assert.deepEqual(or(10, matrix([0, 2])), matrix([true, true])); + assert.deepEqual(or(matrix([0, 2]), 10), matrix([true, true])); + }); + + it('should or dense matrix - array', function () { + assert.deepEqual(or(matrix([0, 1, 0, 12]), [0, 0, 1, 22]), matrix([false, true, true, true])); + assert.deepEqual(or(matrix([]), []), matrix([])); + }); + + it('should or dense matrix - dense matrix', function () { + assert.deepEqual(or(matrix([0, 1, 0, 12]), matrix([0, 0, 1, 22])), matrix([false, true, true, true])); + assert.deepEqual(or(matrix([]), matrix([])), matrix([])); + }); + + it('should or dense matrix - sparse matrix', function () { + assert.deepEqual(or(matrix([[0, 1], [0, 12]]), sparse([[0, 0], [1, 22]])), matrix([[false, true], [true, true]])); + }); + }); + + describe('SparseMatrix', function () { + + it('should or sparse matrix - scalar', function () { + assert.deepEqual(or(10, sparse([[0], [2]])), matrix([[true], [true]])); + assert.deepEqual(or(sparse([[0], [2]]), 10), matrix([[true], [true]])); + }); + + it('should or sparse matrix - array', function () { + assert.deepEqual(or(sparse([[0, 1], [0, 12]]), [[0, 0], [1, 22]]), matrix([[false, true], [true, true]])); + }); + + it('should or sparse matrix - dense matrix', function () { + assert.deepEqual(or(sparse([[0, 1], [0, 12]]), matrix([[0, 0], [1, 22]])), matrix([[false, true], [true, true]])); + }); + + it('should or sparse matrix - sparse matrix', function () { + assert.deepEqual(or(sparse([[0, 1], [0, 12]]), sparse([[0, 0], [1, 22]])), sparse([[false, true], [true, true]])); + }); }); it('should throw an error in case of invalid number of arguments', function () { - assert.throws(function () {or(1)}, /TypeError: Too few arguments/); - assert.throws(function () {or(1, 2, 3)}, /TypeError: Too many arguments/); + assert.throws(function () {or(1);}, /TypeError: Too few arguments/); + assert.throws(function () {or(1, 2, 3);}, /TypeError: Too many arguments/); }); it('should throw an error in case of invalid type of arguments', function () { - assert.throws(function () {or(new Date(), true)}, /TypeError: Unexpected type of argument/); - assert.throws(function () {or(true, new Date())}, /TypeError: Unexpected type of argument/); - assert.throws(function () {or(true, 'foo')}, /TypeError: Unexpected type of argument/); - assert.throws(function () {or('foo', true)}, /TypeError: Unexpected type of argument/); - assert.throws(function () {or(true, undefined)}, /TypeError: Unexpected type of argument/); - assert.throws(function () {or(undefined, true)}, /TypeError: Unexpected type of argument/); + assert.throws(function () {or(new Date(), true);}, /TypeError: Unexpected type of argument/); + assert.throws(function () {or(true, new Date());}, /TypeError: Unexpected type of argument/); + assert.throws(function () {or(true, 'foo');}, /TypeError: Unexpected type of argument/); + assert.throws(function () {or('foo', true);}, /TypeError: Unexpected type of argument/); + assert.throws(function () {or(true, undefined);}, /TypeError: Unexpected type of argument/); + assert.throws(function () {or(undefined, true);}, /TypeError: Unexpected type of argument/); }); it('should LaTeX or', function () { var expression = math.parse('or(1,2)'); assert.equal(expression.toTex(), '\\left(1\\vee2\\right)'); }); - }); diff --git a/test/function/logical/xor.test.js b/test/function/logical/xor.test.js index 1ed22a060..32f90d996 100644 --- a/test/function/logical/xor.test.js +++ b/test/function/logical/xor.test.js @@ -4,6 +4,7 @@ var assert = require('assert'), bignumber = math.bignumber, complex = math.complex, matrix = math.matrix, + sparse = math.sparse, unit = math.unit, xor = math.xor; @@ -127,23 +128,68 @@ describe('xor', function () { assert.deepEqual(xor([], []), []); }); - it('should xor mixed numbers and arrays', function () { - assert.deepEqual(xor(10, [0, 2]), [true, false]); - assert.deepEqual(xor([0, 2], 10), [true, false]); - assert.deepEqual(xor(0, [0, 2]), [false, true]); - assert.deepEqual(xor([0, 2], 0), [false, true]); + describe('Array', function () { + + it('should xor array - scalar', function () { + assert.deepEqual(xor(10, [0, 2]), [true, false]); + assert.deepEqual(xor([0, 2], 10), [true, false]); + }); + + it('should xor array - array', function () { + assert.deepEqual(xor([0, 1, 0, 12], [0, 0, 1, 22]), [false, true, true, false]); + assert.deepEqual(xor([], []), []); + }); + + it('should xor array - dense matrix', function () { + assert.deepEqual(xor([0, 1, 0, 12], matrix([0, 0, 1, 22])), matrix([false, true, true, false])); + assert.deepEqual(xor([], matrix([])), matrix([])); + }); + + it('should xor array - sparse matrix', function () { + assert.deepEqual(xor([[0, 1], [0, 12]], sparse([[0, 0], [1, 22]])), matrix([[false, true], [true, false]])); + }); }); - it('should xor two matrices', function () { - assert.deepEqual(xor(matrix([0, 1, 0, 12]), matrix([0, 0, 1, 22])), matrix([false, true, true, false])); - assert.deepEqual(xor(matrix([]), matrix([])), matrix([])); + describe('DenseMatrix', function () { + + it('should xor dense matrix - scalar', function () { + assert.deepEqual(xor(10, matrix([0, 2])), matrix([true, false])); + assert.deepEqual(xor(matrix([0, 2]), 10), matrix([true, false])); + }); + + it('should xor dense matrix - array', function () { + assert.deepEqual(xor(matrix([0, 1, 0, 12]), [0, 0, 1, 22]), matrix([false, true, true, false])); + assert.deepEqual(xor(matrix([]), []), matrix([])); + }); + + it('should xor dense matrix - dense matrix', function () { + assert.deepEqual(xor(matrix([0, 1, 0, 12]), matrix([0, 0, 1, 22])), matrix([false, true, true, false])); + assert.deepEqual(xor(matrix([]), matrix([])), matrix([])); + }); + + it('should xor dense matrix - sparse matrix', function () { + assert.deepEqual(xor(matrix([[0, 1], [0, 12]]), sparse([[0, 0], [1, 22]])), matrix([[false, true], [true, false]])); + }); }); - it('should xor mixed numbers and matrices', function () { - assert.deepEqual(xor(10, matrix([0, 2])), matrix([true, false])); - assert.deepEqual(xor(matrix([0, 2]), 10), matrix([true, false])); - assert.deepEqual(xor(0, matrix([0, 2])), matrix([false, true])); - assert.deepEqual(xor(matrix([0, 2]), 0), matrix([false, true])); + describe('SparseMatrix', function () { + + it('should xor sparse matrix - scalar', function () { + assert.deepEqual(xor(10, sparse([[0], [2]])), matrix([[true], [false]])); + assert.deepEqual(xor(sparse([[0], [2]]), 10), matrix([[true], [false]])); + }); + + it('should xor sparse matrix - array', function () { + assert.deepEqual(xor(sparse([[0, 1], [0, 12]]), [[0, 0], [1, 22]]), matrix([[false, true], [true, false]])); + }); + + it('should xor sparse matrix - dense matrix', function () { + assert.deepEqual(xor(sparse([[0, 1], [0, 12]]), matrix([[0, 0], [1, 22]])), matrix([[false, true], [true, false]])); + }); + + it('should xor sparse matrix - sparse matrix', function () { + assert.deepEqual(xor(sparse([[0, 1], [0, 12]]), sparse([[0, 0], [1, 22]])), matrix([[false, true], [true, false]])); + }); }); it('should throw an error in case of invalid number of arguments', function () { @@ -164,5 +210,4 @@ describe('xor', function () { var expression = math.parse('xor(1,2)'); assert.equal(expression.toTex(), '\\left(1\\veebar2\\right)'); }); - }); diff --git a/test/function/matrix/transpose.test.js b/test/function/matrix/transpose.test.js index fb45edaa1..edf39f40f 100644 --- a/test/function/matrix/transpose.test.js +++ b/test/function/matrix/transpose.test.js @@ -39,16 +39,25 @@ describe('transpose', function() { it('should transpose a 2d matrix', function() { var m = math.matrix([[1,2,3],[4,5,6]]); - assert.deepEqual(transpose(m).valueOf(), [[1,4],[2,5],[3,6]]); + var t = transpose(m); + assert.deepEqual(t.valueOf(), [[1,4],[2,5],[3,6]]); m = math.matrix([[1,4],[2,5],[3,6]]); - assert.deepEqual(transpose(m).toArray(), [[1,2,3],[4,5,6]]); + t = transpose(m); + assert.deepEqual(t.toArray(), [[1,2,3],[4,5,6]]); m = math.matrix([[1,2],[3,4]]); - assert.deepEqual(transpose(m).valueOf(), [[1,3],[2,4]]); + t = transpose(m); + assert.deepEqual(t.valueOf(), [[1,3],[2,4]]); m = math.matrix([[1,2,3,4]]); - assert.deepEqual(transpose(m).valueOf(), [[1],[2],[3],[4]]); + t = transpose(m); + assert.deepEqual(t.valueOf(), [[1],[2],[3],[4]]); + + m = math.matrix([[1,2,3,4]], 'dense', 'number'); + t = transpose(m); + assert.deepEqual(t.valueOf(), [[1],[2],[3],[4]]); + assert.ok(t.datatype() === 'number'); }); it('should throw an error for invalid matrix transpose', function() { @@ -63,17 +72,22 @@ describe('transpose', function() { describe('SparseMatrix', function () { it('should transpose a 2d matrix', function() { - var m = math.matrix([[1,2,3],[4,5,6]], 'sparse'); - assert.deepEqual(transpose(m).valueOf(), [[1,4],[2,5],[3,6]]); + var m = math.sparse([[1,2,3],[4,5,6]]); + var t = transpose(m); + assert.deepEqual(t.valueOf(), [[1,4],[2,5],[3,6]]); - m = math.matrix([[1,4],[2,5],[3,6]], 'sparse'); - assert.deepEqual(transpose(m).toArray(), [[1,2,3],[4,5,6]]); + m = math.sparse([[1,4],[2,5],[3,6]]); + t = transpose(m); + assert.deepEqual(t.toArray(), [[1,2,3],[4,5,6]]); - m = math.matrix([[1,2],[3,4]], 'sparse'); - assert.deepEqual(transpose(m).valueOf(), [[1,3],[2,4]]); + m = math.sparse([[1,2],[3,4]]); + t = transpose(m); + assert.deepEqual(t.valueOf(), [[1,3],[2,4]]); - m = math.matrix([[1,2,3,4]]); - assert.deepEqual(transpose(m).valueOf(), [[1],[2],[3],[4]]); + m = math.sparse([[1,2,3,4]], 'number'); + t = transpose(m); + assert.deepEqual(t.valueOf(), [[1],[2],[3],[4]]); + assert.ok(t.datatype() === 'number'); }); it('should throw an error for invalid matrix transpose', function() { diff --git a/test/function/relational/compare.test.js b/test/function/relational/compare.test.js index b71c7961e..b37050fc0 100644 --- a/test/function/relational/compare.test.js +++ b/test/function/relational/compare.test.js @@ -1,14 +1,15 @@ // test compare var assert = require('assert'), math = require('../../../index'), - error = require('../../../lib/error/index'), bignumber = math.bignumber, complex = math.complex, matrix = math.matrix, + sparse = math.sparse, unit = math.unit, compare = math.compare; describe('compare', function() { + it('should compare two numbers correctly', function() { assert.equal(compare(2, 3), -1); assert.equal(compare(2, 2), 0); @@ -82,7 +83,7 @@ describe('compare', function() { }); it('should throw an error if comparing a unit with a number', function() { - assert.throws(function () {compare(unit('100cm'), 22)}); + assert.throws(function () {compare(unit('100cm'), 22);}); }); it('should throw an error for two measures of different units', function() { @@ -90,7 +91,7 @@ describe('compare', function() { }); it('should throw an error if comparing a unit with a bignumber', function() { - assert.throws(function () {compare(unit('100cm'), bignumber(22))}); + assert.throws(function () {compare(unit('100cm'), bignumber(22));}); }); it('should perform lexical comparison for two strings', function() { @@ -101,14 +102,64 @@ describe('compare', function() { assert.equal(compare('abc', 'abd'), -1); }); - it('should compare a string an matrix elementwise', function() { - assert.deepEqual(compare('B', ['A', 'B', 'C']), [1, 0, -1]); - assert.deepEqual(compare(['A', 'B', 'C'], 'B'), [-1, 0, 1]); + describe('Array', function () { + + it('should compare array - scalar', function () { + assert.deepEqual(compare('B', ['A', 'B', 'C']), [1, 0, -1]); + assert.deepEqual(compare(['A', 'B', 'C'], 'B'), [-1, 0, 1]); + }); + + it('should compare array - array', function () { + assert.deepEqual(compare([[1, 2, 0], [-1, 0, 2]], [[3, -1, 0], [-2, 1, 0]]), [[-1, 1, 0], [1, -1, 1]]); + }); + + it('should compare array - dense matrix', function () { + assert.deepEqual(compare([[1, 2, 0], [-1, 0, 2]], matrix([[3, -1, 0], [-2, 1, 0]])), matrix([[-1, 1, 0], [1, -1, 1]])); + }); + + it('should compare array - sparse matrix', function () { + assert.deepEqual(compare([[1, 2, 0], [-1, 0, 2]], sparse([[3, -1, 0], [-2, 1, 0]])), matrix([[-1, 1, 0], [1, -1, 1]])); + }); }); + + describe('DenseMatrix', function () { - it('should perform element-wise comparison for two matrices of same size', function() { - assert.deepEqual(compare([1,4,6], [3,4,5]), [-1, 0, 1]); - assert.deepEqual(compare([1,4,6], matrix([3,4,5])), matrix([-1, 0, 1])); + it('should compare dense matrix - scalar', function () { + assert.deepEqual(compare('B', matrix(['A', 'B', 'C'])), matrix([1, 0, -1])); + assert.deepEqual(compare(matrix(['A', 'B', 'C']), 'B'), matrix([-1, 0, 1])); + }); + + it('should compare dense matrix - array', function () { + assert.deepEqual(compare(matrix([[1, 2, 0], [-1, 0, 2]]), [[3, -1, 0], [-2, 1, 0]]), matrix([[-1, 1, 0], [1, -1, 1]])); + }); + + it('should compare dense matrix - dense matrix', function () { + assert.deepEqual(compare(matrix([[1, 2, 0], [-1, 0, 2]]), matrix([[3, -1, 0], [-2, 1, 0]])), matrix([[-1, 1, 0], [1, -1, 1]])); + }); + + it('should compare dense matrix - sparse matrix', function () { + assert.deepEqual(compare(matrix([[1, 2, 0], [-1, 0, 2]]), sparse([[3, -1, 0], [-2, 1, 0]])), matrix([[-1, 1, 0], [1, -1, 1]])); + }); + }); + + describe('SparseMatrix', function () { + + it('should compare sparse matrix - scalar', function () { + assert.deepEqual(compare('B', sparse([['A', 'B'], ['C', 'X']])), matrix([[1, 0], [-1, -1]])); + assert.deepEqual(compare(sparse([['A', 'B'], ['C', 'X']]), 'B'), matrix([[-1, 0], [1, 1]])); + }); + + it('should compare sparse matrix - array', function () { + assert.deepEqual(compare(sparse([[1, 2, 0], [-1, 0, 2]]), [[3, -1, 0], [-2, 1, 0]]), matrix([[-1, 1, 0], [1, -1, 1]])); + }); + + it('should compare sparse matrix - dense matrix', function () { + assert.deepEqual(compare(sparse([[1, 2, 0], [-1, 0, 2]]), matrix([[3, -1, 0], [-2, 1, 0]])), matrix([[-1, 1, 0], [1, -1, 1]])); + }); + + it('should compare sparse matrix - sparse matrix', function () { + assert.deepEqual(compare(sparse([[1, 2, 0], [-1, 0, 2]]), sparse([[3, -1, 0], [-2, 1, 0]])), sparse([[-1, 1, 0], [1, -1, 1]])); + }); }); it('should apply configuration option epsilon', function() { @@ -119,25 +170,24 @@ describe('compare', function() { }); it('should throw an error when comparing complex numbers', function() { - assert.throws(function () {compare(complex(1,1), complex(1,2))}, TypeError); - assert.throws(function () {compare(complex(2,1), 3)}, TypeError); - assert.throws(function () {compare(3, complex(2,4))}, TypeError); - assert.throws(function () {compare(math.bignumber(3), complex(2,4))}, TypeError); - assert.throws(function () {compare(complex(2,4), math.bignumber(3))}, TypeError); + assert.throws(function () {compare(complex(1,1), complex(1,2));}, TypeError); + assert.throws(function () {compare(complex(2,1), 3);}, TypeError); + assert.throws(function () {compare(3, complex(2,4));}, TypeError); + assert.throws(function () {compare(math.bignumber(3), complex(2,4));}, TypeError); + assert.throws(function () {compare(complex(2,4), math.bignumber(3));}, TypeError); }); it('should throw an error if matrices are different sizes', function() { - assert.throws(function () {compare([1,4,6], [3,4])}); + assert.throws(function () {compare([1,4,6], [3,4]);}); }); it('should throw an error in case of invalid number of arguments', function() { - assert.throws(function () {compare(1)}, /TypeError: Too few arguments/); - assert.throws(function () {compare(1, 2, 3)}, /TypeError: Too many arguments/); + assert.throws(function () {compare(1);}, /TypeError: Too few arguments/); + assert.throws(function () {compare(1, 2, 3);}, /TypeError: Too many arguments/); }); it('should LaTeX compare', function () { var expression = math.parse('compare(1,2)'); assert.equal(expression.toTex(), '\\mathrm{compare}\\left(1,2\\right)'); }); - }); diff --git a/test/function/relational/equal.test.js b/test/function/relational/equal.test.js index ecbb5c7d8..c91cb6c74 100644 --- a/test/function/relational/equal.test.js +++ b/test/function/relational/equal.test.js @@ -1,10 +1,10 @@ // test equal var assert = require('assert'), math = require('../../../index'), - error = require('../../../lib/error/index'), bignumber = math.bignumber, complex = math.complex, matrix = math.matrix, + sparse = math.sparse, unit = math.unit, equal = math.equal; @@ -66,8 +66,8 @@ describe('equal', function() { assert.deepEqual(equal(bignumber(2), 3), false); assert.deepEqual(equal(2, bignumber(2)), true); - assert.throws(function () {equal(1/3, bignumber(1).div(3))}, /Cannot implicitly convert a number with >15 significant digits to BigNumber/); - assert.throws(function () {equal(bignumber(1).div(3), 1/3)}, /Cannot implicitly convert a number with >15 significant digits to BigNumber/); + assert.throws(function () {equal(1/3, bignumber(1).div(3));}, /Cannot implicitly convert a number with >15 significant digits to BigNumber/); + assert.throws(function () {equal(bignumber(1).div(3), 1/3);}, /Cannot implicitly convert a number with >15 significant digits to BigNumber/); }); it('should compare mixed booleans and bignumbers', function() { @@ -129,11 +129,11 @@ describe('equal', function() { }); it('should throw an error when comparing a unit with a big number', function() { - assert.throws( function () {equal(math.unit('5 m'), bignumber(10)).toString() }); + assert.throws( function () {equal(math.unit('5 m'), bignumber(10)).toString(); }); }); it('should throw an error when comparing a unit with a number', function() { - assert.throws(function () {equal(unit('100cm'), 22)}); + assert.throws(function () {equal(unit('100cm'), 22);}); }); it('should throw an error for two measures of different units', function() { @@ -146,28 +146,77 @@ describe('equal', function() { assert.equal(equal('hello', 'hello'), true); }); - it('should compare a string an matrix elementwise', function() { - assert.deepEqual(equal('B', ['A', 'B', 'C']), [false, true, false]); - assert.deepEqual(equal(['A', 'B', 'C'], 'B'), [false, true, false]); + describe('Array', function () { + + it('should compare array - scalar', function () { + assert.deepEqual(equal('B', ['A', 'B', 'C']), [false, true, false]); + assert.deepEqual(equal(['A', 'B', 'C'], 'B'), [false, true, false]); + }); + + it('should compare array - array', function () { + assert.deepEqual(equal([[1, 2, 0], [-1, 0, 2]], [[1, -1, 0], [-1, 1, 0]]), [[true, false, true], [true, false, false]]); + }); + + it('should compare array - dense matrix', function () { + assert.deepEqual(equal([[1, 2, 0], [-1, 0, 2]], matrix([[1, -1, 0], [-1, 1, 0]])), matrix([[true, false, true], [true, false, false]])); + }); + + it('should compare array - sparse matrix', function () { + assert.deepEqual(equal([[1, 2, 0], [-1, 0, 2]], sparse([[1, -1, 0], [-1, 1, 0]])), matrix([[true, false, true], [true, false, false]])); + }); + + it('should throw an error if arrays have different sizes', function() { + assert.throws(function () {equal([1,4,5], [3,4]);}); + }); + }); + + describe('DenseMatrix', function () { + + it('should compare dense matrix - scalar', function () { + assert.deepEqual(equal('B', matrix(['A', 'B', 'C'])), matrix([false, true, false])); + assert.deepEqual(equal(matrix(['A', 'B', 'C']), 'B'), matrix([false, true, false])); + }); + + it('should compare dense matrix - array', function () { + assert.deepEqual(equal(matrix([[1, 2, 0], [-1, 0, 2]]), [[1, -1, 0], [-1, 1, 0]]), matrix([[true, false, true], [true, false, false]])); + }); + + it('should compare dense matrix - dense matrix', function () { + assert.deepEqual(equal(matrix([[1, 2, 0], [-1, 0, 2]]), matrix([[1, -1, 0], [-1, 1, 0]])), matrix([[true, false, true], [true, false, false]])); + }); + + it('should compare dense matrix - sparse matrix', function () { + assert.deepEqual(equal(matrix([[1, 2, 0], [-1, 0, 2]]), sparse([[1, -1, 0], [-1, 1, 0]])), matrix([[true, false, true], [true, false, false]])); + }); }); - it('should compare two matrices element wise', function() { - assert.deepEqual(equal([1,4,5], [3,4,5]), [false, true, true]); - assert.deepEqual(equal([1,4,5], matrix([3,4,5])), matrix([false, true, true])); - }); + describe('SparseMatrix', function () { - it('should throw an error if matrices have different sizes', function() { - assert.throws(function () {equal([1,4,5], [3,4])}); - }); + it('should compare sparse matrix - scalar', function () { + assert.deepEqual(equal('B', sparse([['A', 'B'], ['C', 'D']])), matrix([[false, true], [false, false]])); + assert.deepEqual(equal(sparse([['A', 'B'], ['C', 'D']]), 'B'), matrix([[false, true], [false, false]])); + }); + it('should compare sparse matrix - array', function () { + assert.deepEqual(equal(sparse([[1, 2, 0], [-1, 0, 2]]), [[1, -1, 0], [-1, 1, 0]]), matrix([[true, false, true], [true, false, false]])); + }); + + it('should compare sparse matrix - dense matrix', function () { + assert.deepEqual(equal(sparse([[1, 2, 0], [-1, 0, 2]]), matrix([[1, -1, 0], [-1, 1, 0]])), matrix([[true, false, true], [true, false, false]])); + }); + + it('should compare sparse matrix - sparse matrix', function () { + assert.deepEqual(equal(sparse([[1, 2, 0], [-1, 0, 2]]), sparse([[1, -1, 0], [-1, 1, 0]])), matrix([[true, false, true], [true, false, false]])); + }); + }); + it('should throw an error in case of invalid number of arguments', function() { - assert.throws(function () {equal(1)}, /Too few arguments/); - assert.throws(function () {equal(1, 2, 3)}, /Too many arguments/); + assert.throws(function () {equal(1);}, /Too few arguments/); + assert.throws(function () {equal(1, 2, 3);}, /Too many arguments/); }); it('should LaTeX equal', function () { var expression = math.parse('equal(1,2)'); assert.equal(expression.toTex(), '\\left(1=2\\right)'); }); - }); diff --git a/test/function/relational/larger.test.js b/test/function/relational/larger.test.js index 47aee9147..453e25e73 100644 --- a/test/function/relational/larger.test.js +++ b/test/function/relational/larger.test.js @@ -1,14 +1,15 @@ // test larger var assert = require('assert'), math = require('../../../index'), - error = require('../../../lib/error/index'), bignumber = math.bignumber, complex = math.complex, matrix = math.matrix, + sparse = math.sparse, unit = math.unit, larger = math.larger; describe('larger', function() { + it('should compare two numbers correctly', function() { assert.equal(larger(2, 3), false); assert.equal(larger(2, 2), false); @@ -66,8 +67,8 @@ describe('larger', function() { assert.equal(larger(bignumber(2), 3), false); assert.equal(larger(2, bignumber(2)), false); - assert.throws(function () {larger(1/3, bignumber(1).div(3))}, /Cannot implicitly convert a number with >15 significant digits to BigNumber/); - assert.throws(function () {larger(bignumber(1).div(3), 1/3)}, /Cannot implicitly convert a number with >15 significant digits to BigNumber/); + assert.throws(function () {larger(1/3, bignumber(1).div(3));}, /Cannot implicitly convert a number with >15 significant digits to BigNumber/); + assert.throws(function () {larger(bignumber(1).div(3), 1/3);}, /Cannot implicitly convert a number with >15 significant digits to BigNumber/); }); it('should compare mixed booleans and bignumbers', function() { @@ -93,7 +94,7 @@ describe('larger', function() { }); it('should throw an error if comparing a unit with a number', function() { - assert.throws(function () {larger(unit('100cm'), 22)}); + assert.throws(function () {larger(unit('100cm'), 22);}); }); it('should throw an error for two measures of different units', function() { @@ -101,7 +102,7 @@ describe('larger', function() { }); it('should throw an error if comparing a unit with a bignumber', function() { - assert.throws(function () {larger(unit('100cm'), bignumber(22))}); + assert.throws(function () {larger(unit('100cm'), bignumber(22));}); }); it('should perform lexical comparison for two strings', function() { @@ -112,36 +113,89 @@ describe('larger', function() { assert.equal(larger('abc', 'abd'), false); }); - it('should compare a string an matrix elementwise', function() { - assert.deepEqual(larger('B', ['A', 'B', 'C']), [true, false, false]); - assert.deepEqual(larger(['A', 'B', 'C'], 'B'), [false, false, true]); + describe('Array', function () { + + it('should compare array - scalar', function () { + assert.deepEqual(larger('B', ['A', 'B', 'C']), [true, false, false]); + assert.deepEqual(larger(['A', 'B', 'C'], 'B'), [false, false, true]); + }); + + it('should compare array - array', function () { + assert.deepEqual(larger([[1, 2, 0], [-1, 0, 2]], [[1, -1, 0], [-1, 1, 0]]), [[false, true, false], [false, false, true]]); + }); + + it('should compare array - dense matrix', function () { + assert.deepEqual(larger([[1, 2, 0], [-1, 0, 2]], matrix([[1, -1, 0], [-1, 1, 0]])), matrix([[false, true, false], [false, false, true]])); + }); + + it('should compare array - sparse matrix', function () { + assert.deepEqual(larger([[1, 2, 0], [-1, 0, 2]], sparse([[1, -1, 0], [-1, 1, 0]])), matrix([[false, true, false], [false, false, true]])); + }); + + it('should throw an error if arrays have different sizes', function() { + assert.throws(function () {larger([1,4,5], [3,4]);}); + }); }); - it('should perform element-wise comparison for two matrices of same size', function() { - assert.deepEqual(larger([1,4,6], [3,4,5]), [false, false, true]); - assert.deepEqual(larger([1,4,6], matrix([3,4,5])), matrix([false, false, true])); + describe('DenseMatrix', function () { + + it('should compare dense matrix - scalar', function () { + assert.deepEqual(larger('B', matrix(['A', 'B', 'C'])), matrix([true, false, false])); + assert.deepEqual(larger(matrix(['A', 'B', 'C']), 'B'), matrix([false, false, true])); + }); + + it('should compare dense matrix - array', function () { + assert.deepEqual(larger(matrix([[1, 2, 0], [-1, 0, 2]]), [[1, -1, 0], [-1, 1, 0]]), matrix([[false, true, false], [false, false, true]])); + }); + + it('should compare dense matrix - dense matrix', function () { + assert.deepEqual(larger(matrix([[1, 2, 0], [-1, 0, 2]]), matrix([[1, -1, 0], [-1, 1, 0]])), matrix([[false, true, false], [false, false, true]])); + }); + + it('should compare dense matrix - sparse matrix', function () { + assert.deepEqual(larger(matrix([[1, 2, 0], [-1, 0, 2]]), sparse([[1, -1, 0], [-1, 1, 0]])), matrix([[false, true, false], [false, false, true]])); + }); + }); + + describe('SparseMatrix', function () { + + it('should compare sparse matrix - scalar', function () { + assert.deepEqual(larger('B', sparse([['A', 'B'], ['C', 'D']])), matrix([[true, false], [false, false]])); + assert.deepEqual(larger(sparse([['A', 'B'], ['C', 'D']]), 'B'), matrix([[false, false], [true, true]])); + }); + + it('should compare sparse matrix - array', function () { + assert.deepEqual(larger(sparse([[1, 2, 0], [-1, 0, 2]]), [[1, -1, 0], [-1, 1, 0]]), matrix([[false, true, false], [false, false, true]])); + }); + + it('should compare sparse matrix - dense matrix', function () { + assert.deepEqual(larger(sparse([[1, 2, 0], [-1, 0, 2]]), matrix([[1, -1, 0], [-1, 1, 0]])), matrix([[false, true, false], [false, false, true]])); + }); + + it('should compare sparse matrix - sparse matrix', function () { + assert.deepEqual(larger(sparse([[1, 2, 0], [-1, 0, 2]]), sparse([[1, -1, 0], [-1, 1, 0]])), matrix([[false, true, false], [false, false, true]])); + }); }); it('should throw an error when comparing complex numbers', function() { - assert.throws(function () {larger(complex(1,1), complex(1,2))}, TypeError); - assert.throws(function () {larger(complex(2,1), 3)}, TypeError); - assert.throws(function () {larger(3, complex(2,4))}, TypeError); - assert.throws(function () {larger(math.bignumber(3), complex(2,4))}, TypeError); - assert.throws(function () {larger(complex(2,4), math.bignumber(3))}, TypeError); + assert.throws(function () {larger(complex(1,1), complex(1,2));}, TypeError); + assert.throws(function () {larger(complex(2,1), 3);}, TypeError); + assert.throws(function () {larger(3, complex(2,4));}, TypeError); + assert.throws(function () {larger(math.bignumber(3), complex(2,4));}, TypeError); + assert.throws(function () {larger(complex(2,4), math.bignumber(3));}, TypeError); }); it('should throw an error if matrices are different sizes', function() { - assert.throws(function () {larger([1,4,6], [3,4])}); + assert.throws(function () {larger([1,4,6], [3,4]);}); }); it('should throw an error in case of invalid number of arguments', function() { - assert.throws(function () {larger(1)}, /Too few arguments/); - assert.throws(function () {larger(1, 2, 3)}, /Too many arguments/); + assert.throws(function () {larger(1);}, /Too few arguments/); + assert.throws(function () {larger(1, 2, 3);}, /Too many arguments/); }); it('should LaTeX larger', function () { var expression = math.parse('larger(1,2)'); assert.equal(expression.toTex(), '\\left(1>2\\right)'); }); - }); diff --git a/test/function/relational/largerEq.test.js b/test/function/relational/largerEq.test.js index 57513a827..8b08b8fa7 100644 --- a/test/function/relational/largerEq.test.js +++ b/test/function/relational/largerEq.test.js @@ -4,6 +4,7 @@ var assert = require('assert'), bignumber = math.bignumber, complex = math.complex, matrix = math.matrix, + sparse = math.sparse, unit = math.unit, largerEq = math.largerEq; @@ -67,8 +68,8 @@ describe('largerEq', function() { assert.equal(largerEq(bignumber(2), 3), false); assert.equal(largerEq(2, bignumber(2)), true); - assert.throws(function () {largerEq(1/3, bignumber(1).div(3))}, /TypeError: Cannot implicitly convert a number with >15 significant digits to BigNumber/); - assert.throws(function () {largerEq(bignumber(1).div(3), 1/3)}, /TypeError: Cannot implicitly convert a number with >15 significant digits to BigNumber/); + assert.throws(function () {largerEq(1/3, bignumber(1).div(3));}, /TypeError: Cannot implicitly convert a number with >15 significant digits to BigNumber/); + assert.throws(function () {largerEq(bignumber(1).div(3), 1/3);}, /TypeError: Cannot implicitly convert a number with >15 significant digits to BigNumber/); }); it('should compare mixed booleans and bignumbers', function() { @@ -95,7 +96,7 @@ describe('largerEq', function() { }); it('should throw an error if comparing a unit with a number', function() { - assert.throws(function () {largerEq(unit('100cm'), 22)}); + assert.throws(function () {largerEq(unit('100cm'), 22);}); }); it('should throw an error for two measures of different units', function() { @@ -103,7 +104,7 @@ describe('largerEq', function() { }); it('should throw an error if comparing a unit with a bignumber', function() { - assert.throws(function () {largerEq(unit('100cm'), bignumber(22))}); + assert.throws(function () {largerEq(unit('100cm'), bignumber(22));}); }); it('should perform lexical comparison for 2 strings', function() { @@ -113,31 +114,85 @@ describe('largerEq', function() { assert.equal(largerEq('abc', 'abd'), false); }); - it('should compare a string an matrix elementwise', function() { - assert.deepEqual(largerEq('B', ['A', 'B', 'C']), [true, true, false]); - assert.deepEqual(largerEq(['A', 'B', 'C'], 'B'), [false, true, true]); + describe('Array', function () { + + it('should compare array - scalar', function () { + assert.deepEqual(largerEq('B', ['A', 'B', 'C']), [true, true, false]); + assert.deepEqual(largerEq(['A', 'B', 'C'], 'B'), [false, true, true]); + }); + + it('should compare array - array', function () { + assert.deepEqual(largerEq([[1, 2, 0], [-1, 0, 2]], [[1, -1, 0], [-1, 1, 0]]), [[true, true, true], [true, false, true]]); + }); + + it('should compare array - dense matrix', function () { + assert.deepEqual(largerEq([[1, 2, 0], [-1, 0, 2]], matrix([[1, -1, 0], [-1, 1, 0]])), matrix([[true, true, true], [true, false, true]])); + }); + + it('should compare array - sparse matrix', function () { + assert.deepEqual(largerEq([[1, 2, 0], [-1, 0, 2]], sparse([[1, -1, 0], [-1, 1, 0]])), matrix([[true, true, true], [true, false, true]])); + }); + + it('should throw an error if arrays have different sizes', function() { + assert.throws(function () {largerEq([1,4,5], [3,4]);}); + }); }); - it('should perform element-wise comparison for two matrices of the same size', function() { - assert.deepEqual(largerEq([1,4,6], [3,4,5]), [false, true, true]); - assert.deepEqual(largerEq([1,4,6], matrix([3,4,5])), matrix([false, true, true])); + describe('DenseMatrix', function () { + + it('should compare dense matrix - scalar', function () { + assert.deepEqual(largerEq('B', matrix(['A', 'B', 'C'])), matrix([true, true, false])); + assert.deepEqual(largerEq(matrix(['A', 'B', 'C']), 'B'), matrix([false, true, true])); + }); + + it('should compare dense matrix - array', function () { + assert.deepEqual(largerEq(matrix([[1, 2, 0], [-1, 0, 2]]), [[1, -1, 0], [-1, 1, 0]]), matrix([[true, true, true], [true, false, true]])); + }); + + it('should compare dense matrix - dense matrix', function () { + assert.deepEqual(largerEq(matrix([[1, 2, 0], [-1, 0, 2]]), matrix([[1, -1, 0], [-1, 1, 0]])), matrix([[true, true, true], [true, false, true]])); + }); + + it('should compare dense matrix - sparse matrix', function () { + assert.deepEqual(largerEq(matrix([[1, 2, 0], [-1, 0, 2]]), sparse([[1, -1, 0], [-1, 1, 0]])), matrix([[true, true, true], [true, false, true]])); + }); + }); + + describe('SparseMatrix', function () { + + it('should compare sparse matrix - scalar', function () { + assert.deepEqual(largerEq('B', sparse([['A', 'B'], ['C', 'D']])), matrix([[true, true], [false, false]])); + assert.deepEqual(largerEq(sparse([['A', 'B'], ['C', 'D']]), 'B'), matrix([[false, true], [true, true]])); + }); + + it('should compare sparse matrix - array', function () { + assert.deepEqual(largerEq(sparse([[1, 2, 0], [-1, 0, 2]]), [[1, -1, 0], [-1, 1, 0]]), matrix([[true, true, true], [true, false, true]])); + }); + + it('should compare sparse matrix - dense matrix', function () { + assert.deepEqual(largerEq(sparse([[1, 2, 0], [-1, 0, 2]]), matrix([[1, -1, 0], [-1, 1, 0]])), matrix([[true, true, true], [true, false, true]])); + }); + + it('should compare sparse matrix - sparse matrix', function () { + assert.deepEqual(largerEq(sparse([[1, 2, 0], [-1, 0, 2]]), sparse([[1, -1, 0], [-1, 1, 0]])), matrix([[true, true, true], [true, false, true]])); + }); }); it('should throw an error when comparing complex numbers', function() { - assert.throws(function () {largerEq(complex(1,1), complex(1,2))}, TypeError); - assert.throws(function () {largerEq(complex(2,1), 3)}, TypeError); - assert.throws(function () {largerEq(3, complex(2,4))}, TypeError); - assert.throws(function () {largerEq(math.bignumber(3), complex(2,4))}, TypeError); - assert.throws(function () {largerEq(complex(2,4), math.bignumber(3))}, TypeError); + assert.throws(function () {largerEq(complex(1,1), complex(1,2));}, TypeError); + assert.throws(function () {largerEq(complex(2,1), 3);}, TypeError); + assert.throws(function () {largerEq(3, complex(2,4));}, TypeError); + assert.throws(function () {largerEq(math.bignumber(3), complex(2,4));}, TypeError); + assert.throws(function () {largerEq(complex(2,4), math.bignumber(3));}, TypeError); }); it('should throw an error if comparing two matrices of different sizes', function() { - assert.throws(function () {largerEq([1,4,6], [3,4])}); + assert.throws(function () {largerEq([1,4,6], [3,4]);}); }); it('should throw an error in case of invalid number of arguments', function() { - assert.throws(function () {largerEq(1)}, /TypeError: Too few arguments/); - assert.throws(function () {largerEq(1, 2, 3)}, /TypeError: Too many arguments/); + assert.throws(function () {largerEq(1);}, /TypeError: Too few arguments/); + assert.throws(function () {largerEq(1, 2, 3);}, /TypeError: Too many arguments/); }); it('should LaTeX largerEq', function () { diff --git a/test/function/relational/smaller.test.js b/test/function/relational/smaller.test.js index a72c07e95..f13881977 100644 --- a/test/function/relational/smaller.test.js +++ b/test/function/relational/smaller.test.js @@ -1,10 +1,10 @@ // test smaller var assert = require('assert'), math = require('../../../index'), - error = require('../../../lib/error/index'), bignumber = math.bignumber, complex = math.complex, matrix = math.matrix, + sparse = math.sparse, unit = math.unit, smaller = math.smaller; @@ -72,8 +72,8 @@ describe('smaller', function() { //assert.equal(smaller(1/3, bignumber(1).div(3)), false); //assert.equal(smaller(bignumber(1).div(3), 1/3), false); - assert.throws(function () {smaller(1/3, bignumber(1).div(3))}, /Cannot implicitly convert a number with >15 significant digits to BigNumber/); - assert.throws(function () {smaller(bignumber(1).div(3), 1/3)}, /Cannot implicitly convert a number with >15 significant digits to BigNumber/); + assert.throws(function () {smaller(1/3, bignumber(1).div(3));}, /Cannot implicitly convert a number with >15 significant digits to BigNumber/); + assert.throws(function () {smaller(bignumber(1).div(3), 1/3);}, /Cannot implicitly convert a number with >15 significant digits to BigNumber/); }); it('should compare mixed booleans and bignumbers', function() { @@ -101,7 +101,7 @@ describe('smaller', function() { }); it('should throw an error if comparing a unit and a number', function() { - assert.throws(function () {smaller(unit('100cm'), 22)}); + assert.throws(function () {smaller(unit('100cm'), 22);}); }); it('should throw an error for two measures of different units', function() { @@ -109,7 +109,7 @@ describe('smaller', function() { }); it('should throw an error if comparing a unit and a bignumber', function() { - assert.throws(function () {smaller(unit('100cm'), bignumber(22))}); + assert.throws(function () {smaller(unit('100cm'), bignumber(22));}); }); it('should perform lexical comparison on two strings', function() { @@ -119,31 +119,85 @@ describe('smaller', function() { assert.equal(smaller('abc', 'abd'), true); }); - it('should compare a string and matrix elementwise', function() { - assert.deepEqual(smaller('B', ['A', 'B', 'C']), [false, false, true]); - assert.deepEqual(smaller(['A', 'B', 'C'], 'B'), [true, false, false]); + describe('Array', function () { + + it('should compare array - scalar', function () { + assert.deepEqual(smaller('B', ['A', 'B', 'C']), [false, false, true]); + assert.deepEqual(smaller(['A', 'B', 'C'], 'B'), [true, false, false]); + }); + + it('should compare array - array', function () { + assert.deepEqual(smaller([[1, 2, 0], [-1, 0, 2]], [[1, -1, 0], [-1, 1, 0]]), [[false, false, false], [false, true, false]]); + }); + + it('should compare array - dense matrix', function () { + assert.deepEqual(smaller([[1, 2, 0], [-1, 0, 2]], matrix([[1, -1, 0], [-1, 1, 0]])), matrix([[false, false, false], [false, true, false]])); + }); + + it('should compare array - sparse matrix', function () { + assert.deepEqual(smaller([[1, 2, 0], [-1, 0, 2]], sparse([[1, -1, 0], [-1, 1, 0]])), matrix([[false, false, false], [false, true, false]])); + }); + + it('should throw an error if arrays have different sizes', function() { + assert.throws(function () {smaller([1,4,5], [3,4]);}); + }); }); - it('should perform element-wise comparison on two matrices of same size', function() { - assert.deepEqual(smaller([1,4,6], [3,4,5]), [true, false, false]); - assert.deepEqual(smaller([1,4,6], matrix([3,4,5])), matrix([true, false, false])); + describe('DenseMatrix', function () { + + it('should compare dense matrix - scalar', function () { + assert.deepEqual(smaller('B', matrix(['A', 'B', 'C'])), matrix([false, false, true])); + assert.deepEqual(smaller(matrix(['A', 'B', 'C']), 'B'), matrix([true, false, false])); + }); + + it('should compare dense matrix - array', function () { + assert.deepEqual(smaller(matrix([[1, 2, 0], [-1, 0, 2]]), [[1, -1, 0], [-1, 1, 0]]), matrix([[false, false, false], [false, true, false]])); + }); + + it('should compare dense matrix - dense matrix', function () { + assert.deepEqual(smaller(matrix([[1, 2, 0], [-1, 0, 2]]), matrix([[1, -1, 0], [-1, 1, 0]])), matrix([[false, false, false], [false, true, false]])); + }); + + it('should compare dense matrix - sparse matrix', function () { + assert.deepEqual(smaller(matrix([[1, 2, 0], [-1, 0, 2]]), sparse([[1, -1, 0], [-1, 1, 0]])), matrix([[false, false, false], [false, true, false]])); + }); + }); + + describe('SparseMatrix', function () { + + it('should compare sparse matrix - scalar', function () { + assert.deepEqual(smaller('B', sparse([['A', 'B'], ['C', 'D']])), matrix([[false, false], [true, true]])); + assert.deepEqual(smaller(sparse([['A', 'B'], ['C', 'D']]), 'B'), matrix([[true, false], [false, false]])); + }); + + it('should compare sparse matrix - array', function () { + assert.deepEqual(smaller(sparse([[1, 2, 0], [-1, 0, 2]]), [[1, -1, 0], [-1, 1, 0]]), matrix([[false, false, false], [false, true, false]])); + }); + + it('should compare sparse matrix - dense matrix', function () { + assert.deepEqual(smaller(sparse([[1, 2, 0], [-1, 0, 2]]), matrix([[1, -1, 0], [-1, 1, 0]])), matrix([[false, false, false], [false, true, false]])); + }); + + it('should compare sparse matrix - sparse matrix', function () { + assert.deepEqual(smaller(sparse([[1, 2, 0], [-1, 0, 2]]), sparse([[1, -1, 0], [-1, 1, 0]])), matrix([[false, false, false], [false, true, false]])); + }); }); it('should throw an error when comparing complex numbers', function() { - assert.throws(function () {smaller(complex(1,1), complex(1,2))}, TypeError); - assert.throws(function () {smaller(complex(2,1), 3)}, TypeError); - assert.throws(function () {smaller(3, complex(2,4))}, TypeError); - assert.throws(function () {smaller(math.bignumber(3), complex(2,4))}, TypeError); - assert.throws(function () {smaller(complex(2,4), math.bignumber(3))}, TypeError); + assert.throws(function () {smaller(complex(1,1), complex(1,2));}, TypeError); + assert.throws(function () {smaller(complex(2,1), 3);}, TypeError); + assert.throws(function () {smaller(3, complex(2,4));}, TypeError); + assert.throws(function () {smaller(math.bignumber(3), complex(2,4));}, TypeError); + assert.throws(function () {smaller(complex(2,4), math.bignumber(3));}, TypeError); }); it('should throw an error with two matrices of different sizes', function () { - assert.throws(function () {smaller([1,4,6], [3,4])}); + assert.throws(function () {smaller([1,4,6], [3,4]);}); }); it('should throw an error in case of invalid number of arguments', function() { - assert.throws(function () {smaller(1)}, /TypeError: Too few arguments/); - assert.throws(function () {smaller(1, 2, 3)}, /TypeError: Too many arguments/); + assert.throws(function () {smaller(1);}, /TypeError: Too few arguments/); + assert.throws(function () {smaller(1, 2, 3);}, /TypeError: Too many arguments/); }); it('should LaTeX smaller', function () { diff --git a/test/function/relational/smallerEq.test.js b/test/function/relational/smallerEq.test.js index 46a286b7d..ef83f963d 100644 --- a/test/function/relational/smallerEq.test.js +++ b/test/function/relational/smallerEq.test.js @@ -4,6 +4,7 @@ var assert = require('assert'), bignumber = math.bignumber, complex = math.complex, matrix = math.matrix, + sparse = math.sparse, unit = math.unit, smallerEq = math.smallerEq; @@ -69,8 +70,8 @@ describe('smallerEq', function() { assert.deepEqual(smallerEq(bignumber(2), 3), true); assert.deepEqual(smallerEq(2, bignumber(2)), true); - assert.throws(function () {smallerEq(1/3, bignumber(1).div(3))}, /TypeError: Cannot implicitly convert a number with >15 significant digits to BigNumber/); - assert.throws(function () {smallerEq(bignumber(1).div(3), 1/3)}, /TypeError: Cannot implicitly convert a number with >15 significant digits to BigNumber/); + assert.throws(function () {smallerEq(1/3, bignumber(1).div(3));}, /TypeError: Cannot implicitly convert a number with >15 significant digits to BigNumber/); + assert.throws(function () {smallerEq(bignumber(1).div(3), 1/3);}, /TypeError: Cannot implicitly convert a number with >15 significant digits to BigNumber/); }); it('should compare mixed booleans and bignumbers', function() { @@ -98,8 +99,8 @@ describe('smallerEq', function() { }); it('should throw an error if comparing a unit with a number', function() { - assert.throws(function () {smallerEq(unit('100cm'), 22)}); - assert.throws(function () {smallerEq(22, unit('100cm'))}); + assert.throws(function () {smallerEq(unit('100cm'), 22);}); + assert.throws(function () {smallerEq(22, unit('100cm'));}); }); it('should throw an error for two measures of different units', function() { @@ -107,8 +108,8 @@ describe('smallerEq', function() { }); it('should throw an error if comparing a unit with a bignumber', function() { - assert.throws(function () {smallerEq(unit('100cm'), bignumber(22))}); - assert.throws(function () {smallerEq(bignumber(22), unit('100cm'))}); + assert.throws(function () {smallerEq(unit('100cm'), bignumber(22));}); + assert.throws(function () {smallerEq(bignumber(22), unit('100cm'));}); }); it('should perform lexical comparison of two strings', function() { @@ -118,31 +119,85 @@ describe('smallerEq', function() { assert.equal(smallerEq('abc', 'abd'), true); }); - it('should compare a string an matrix elementwise', function() { - assert.deepEqual(smallerEq('B', ['A', 'B', 'C']), [false, true, true]); - assert.deepEqual(smallerEq(['A', 'B', 'C'], 'B'), [true, true, false]); + describe('Array', function () { + + it('should compare array - scalar', function () { + assert.deepEqual(smallerEq('B', ['A', 'B', 'C']), [false, true, true]); + assert.deepEqual(smallerEq(['A', 'B', 'C'], 'B'), [true, true, false]); + }); + + it('should compare array - array', function () { + assert.deepEqual(smallerEq([[1, 2, 0], [-1, 0, 2]], [[1, -1, 0], [-1, 1, 0]]), [[true, false, true], [true, true, false]]); + }); + + it('should compare array - dense matrix', function () { + assert.deepEqual(smallerEq([[1, 2, 0], [-1, 0, 2]], matrix([[1, -1, 0], [-1, 1, 0]])), matrix([[true, false, true], [true, true, false]])); + }); + + it('should compare array - sparse matrix', function () { + assert.deepEqual(smallerEq([[1, 2, 0], [-1, 0, 2]], sparse([[1, -1, 0], [-1, 1, 0]])), matrix([[true, false, true], [true, true, false]])); + }); + + it('should throw an error if arrays have different sizes', function() { + assert.throws(function () {smallerEq([1,4,5], [3,4]);}); + }); }); - it('should perform element-wise comparison on two matrices', function() { - assert.deepEqual(smallerEq([1,4,6], [3,4,5]), [true, true, false]); - assert.deepEqual(smallerEq([1,4,6], matrix([3,4,5])), matrix([true, true, false])); + describe('DenseMatrix', function () { + + it('should compare dense matrix - scalar', function () { + assert.deepEqual(smallerEq('B', matrix(['A', 'B', 'C'])), matrix([false, true, true])); + assert.deepEqual(smallerEq(matrix(['A', 'B', 'C']), 'B'), matrix([true, true, false])); + }); + + it('should compare dense matrix - array', function () { + assert.deepEqual(smallerEq(matrix([[1, 2, 0], [-1, 0, 2]]), [[1, -1, 0], [-1, 1, 0]]), matrix([[true, false, true], [true, true, false]])); + }); + + it('should compare dense matrix - dense matrix', function () { + assert.deepEqual(smallerEq(matrix([[1, 2, 0], [-1, 0, 2]]), matrix([[1, -1, 0], [-1, 1, 0]])), matrix([[true, false, true], [true, true, false]])); + }); + + it('should compare dense matrix - sparse matrix', function () { + assert.deepEqual(smallerEq(matrix([[1, 2, 0], [-1, 0, 2]]), sparse([[1, -1, 0], [-1, 1, 0]])), matrix([[true, false, true], [true, true, false]])); + }); + }); + + describe('SparseMatrix', function () { + + it('should compare sparse matrix - scalar', function () { + assert.deepEqual(smallerEq('B', sparse([['A', 'B'], ['C', 'D']])), matrix([[false, true], [true, true]])); + assert.deepEqual(smallerEq(sparse([['A', 'B'], ['C', 'D']]), 'B'), matrix([[true, true], [false, false]])); + }); + + it('should compare sparse matrix - array', function () { + assert.deepEqual(smallerEq(sparse([[1, 2, 0], [-1, 0, 2]]), [[1, -1, 0], [-1, 1, 0]]), matrix([[true, false, true], [true, true, false]])); + }); + + it('should compare sparse matrix - dense matrix', function () { + assert.deepEqual(smallerEq(sparse([[1, 2, 0], [-1, 0, 2]]), matrix([[1, -1, 0], [-1, 1, 0]])), matrix([[true, false, true], [true, true, false]])); + }); + + it('should compare sparse matrix - sparse matrix', function () { + assert.deepEqual(smallerEq(sparse([[1, 2, 0], [-1, 0, 2]]), sparse([[1, -1, 0], [-1, 1, 0]])), matrix([[true, false, true], [true, true, false]])); + }); }); it('should throw an error when comparing complex numbers', function() { - assert.throws(function () {smallerEq(complex(1,1), complex(1,2))}, TypeError); - assert.throws(function () {smallerEq(complex(2,1), 3)}, TypeError); - assert.throws(function () {smallerEq(3, complex(2,4))}, TypeError); - assert.throws(function () {smallerEq(math.bignumber(3), complex(2,4))}, TypeError); - assert.throws(function () {smallerEq(complex(2,4), math.bignumber(3))}, TypeError); + assert.throws(function () {smallerEq(complex(1,1), complex(1,2));}, TypeError); + assert.throws(function () {smallerEq(complex(2,1), 3);}, TypeError); + assert.throws(function () {smallerEq(3, complex(2,4));}, TypeError); + assert.throws(function () {smallerEq(math.bignumber(3), complex(2,4));}, TypeError); + assert.throws(function () {smallerEq(complex(2,4), math.bignumber(3));}, TypeError); }); it('should throw an error with two matrices of different sizes', function () { - assert.throws(function () {smallerEq([1,4,6], [3,4])}); + assert.throws(function () {smallerEq([1,4,6], [3,4]);}); }); it('should throw an error in case of invalid number of arguments', function() { - assert.throws(function () {smallerEq(1)}, /TypeError: Too few arguments/); - assert.throws(function () {smallerEq(1, 2, 3)}, /TypeError: Too many arguments/); + assert.throws(function () {smallerEq(1);}, /TypeError: Too few arguments/); + assert.throws(function () {smallerEq(1, 2, 3);}, /TypeError: Too many arguments/); }); it('should LaTeX smallerEq', function () { diff --git a/test/function/relational/unequal.test.js b/test/function/relational/unequal.test.js index ee77e483a..a70257374 100644 --- a/test/function/relational/unequal.test.js +++ b/test/function/relational/unequal.test.js @@ -4,6 +4,7 @@ var assert = require('assert'), bignumber = math.bignumber, complex = math.complex, matrix = math.matrix, + sparse = math.sparse, unit = math.unit, unequal = math.unequal; @@ -66,8 +67,8 @@ describe('unequal', function() { assert.deepEqual(unequal(bignumber(2), 3), true); assert.deepEqual(unequal(2, bignumber(2)), false); - assert.throws(function () {unequal(1/3, bignumber(1).div(3))}, /TypeError: Cannot implicitly convert a number with >15 significant digits to BigNumber/); - assert.throws(function () {unequal(bignumber(1).div(3), 1/3)}, /TypeError: Cannot implicitly convert a number with >15 significant digits to BigNumber/); + assert.throws(function () {unequal(1/3, bignumber(1).div(3));}, /TypeError: Cannot implicitly convert a number with >15 significant digits to BigNumber/); + assert.throws(function () {unequal(bignumber(1).div(3), 1/3);}, /TypeError: Cannot implicitly convert a number with >15 significant digits to BigNumber/); }); it('should compare mixed booleans and bignumbers', function() { @@ -128,13 +129,13 @@ describe('unequal', function() { }); it('should throw an error when comparing numbers and units', function() { - assert.throws(function () {unequal(unit('100cm'), 22)}); - assert.throws(function () {unequal(22, unit('100cm'))}); + assert.throws(function () {unequal(unit('100cm'), 22);}); + assert.throws(function () {unequal(22, unit('100cm'));}); }); it('should throw an error when comparing bignumbers and units', function() { - assert.throws(function () {unequal(unit('100cm'), bignumber(22))}); - assert.throws(function () {unequal(bignumber(22), unit('100cm'))}); + assert.throws(function () {unequal(unit('100cm'), bignumber(22));}); + assert.throws(function () {unequal(bignumber(22), unit('100cm'));}); }); it('should throw an error for two measures of different units', function() { @@ -147,23 +148,77 @@ describe('unequal', function() { assert.equal(unequal('hello', 'hello'), false); }); - it('should compare a string an matrix elementwise', function() { - assert.deepEqual(unequal('B', ['A', 'B', 'C']), [true, false, true]); - assert.deepEqual(unequal(['A', 'B', 'C'], 'B'), [true, false, true]); + describe('Array', function () { + + it('should compare array - scalar', function () { + assert.deepEqual(unequal('B', ['A', 'B', 'C']), [true, false, true]); + assert.deepEqual(unequal(['A', 'B', 'C'], 'B'), [true, false, true]); + }); + + it('should compare array - array', function () { + assert.deepEqual(unequal([[1, 2, 0], [-1, 0, 2]], [[1, -1, 0], [-1, 1, 0]]), [[false, true, false], [false, true, true]]); + }); + + it('should compare array - dense matrix', function () { + assert.deepEqual(unequal([[1, 2, 0], [-1, 0, 2]], matrix([[1, -1, 0], [-1, 1, 0]])), matrix([[false, true, false], [false, true, true]])); + }); + + it('should compare array - sparse matrix', function () { + assert.deepEqual(unequal([[1, 2, 0], [-1, 0, 2]], sparse([[1, -1, 0], [-1, 1, 0]])), matrix([[false, true, false], [false, true, true]])); + }); + + it('should throw an error if arrays have different sizes', function() { + assert.throws(function () {unequal([1,4,5], [3,4]);}); + }); }); - it('should compare two matrices element wise', function() { - assert.deepEqual(unequal([1,4,5], [3,4,5]), [true, false, false]); - assert.deepEqual(unequal([1,4,5], matrix([3,4,5])), matrix([true, false, false])); + describe('DenseMatrix', function () { + + it('should compare dense matrix - scalar', function () { + assert.deepEqual(unequal('B', matrix(['A', 'B', 'C'])), matrix([true, false, true])); + assert.deepEqual(unequal(matrix(['A', 'B', 'C']), 'B'), matrix([true, false, true])); + }); + + it('should compare dense matrix - array', function () { + assert.deepEqual(unequal(matrix([[1, 2, 0], [-1, 0, 2]]), [[1, -1, 0], [-1, 1, 0]]), matrix([[false, true, false], [false, true, true]])); + }); + + it('should compare dense matrix - dense matrix', function () { + assert.deepEqual(unequal(matrix([[1, 2, 0], [-1, 0, 2]]), matrix([[1, -1, 0], [-1, 1, 0]])), matrix([[false, true, false], [false, true, true]])); + }); + + it('should compare dense matrix - sparse matrix', function () { + assert.deepEqual(unequal(matrix([[1, 2, 0], [-1, 0, 2]]), sparse([[1, -1, 0], [-1, 1, 0]])), matrix([[false, true, false], [false, true, true]])); + }); + }); + + describe('SparseMatrix', function () { + + it('should compare sparse matrix - scalar', function () { + assert.deepEqual(unequal('B', sparse([['A', 'B'], ['C', 'D']])), matrix([[true, false], [true, true]])); + assert.deepEqual(unequal(sparse([['A', 'B'], ['C', 'D']]), 'B'), matrix([[true, false], [true, true]])); + }); + + it('should compare sparse matrix - array', function () { + assert.deepEqual(unequal(sparse([[1, 2, 0], [-1, 0, 2]]), [[1, -1, 0], [-1, 1, 0]]), matrix([[false, true, false], [false, true, true]])); + }); + + it('should compare sparse matrix - dense matrix', function () { + assert.deepEqual(unequal(sparse([[1, 2, 0], [-1, 0, 2]]), matrix([[1, -1, 0], [-1, 1, 0]])), matrix([[false, true, false], [false, true, true]])); + }); + + it('should compare sparse matrix - sparse matrix', function () { + assert.deepEqual(unequal(sparse([[1, 2, 0], [-1, 0, 2]]), sparse([[1, -1, 0], [-1, 1, 0]])), matrix([[false, true, false], [false, true, true]])); + }); }); it('should throw an error if matrices have different sizes', function() { - assert.throws(function () {unequal([1,4,5], [3,4])}); + assert.throws(function () {unequal([1,4,5], [3,4]);}); }); it('should throw an error in case of invalid number of arguments', function() { - assert.throws(function () {unequal(1)}, /TypeError: Too few arguments/); - assert.throws(function () {unequal(1, 2, 3)}, /TypeError: Too many arguments/); + assert.throws(function () {unequal(1);}, /TypeError: Too few arguments/); + assert.throws(function () {unequal(1, 2, 3);}, /TypeError: Too many arguments/); }); it('should LaTeX unequal', function () { diff --git a/test/function/trigonometry/atan2.test.js b/test/function/trigonometry/atan2.test.js index c30abc28d..c856e21b7 100644 --- a/test/function/trigonometry/atan2.test.js +++ b/test/function/trigonometry/atan2.test.js @@ -1,11 +1,11 @@ // test atan2 var assert = require('assert'), - error = require('../../../lib/error/index'), math = require('../../../index'), approx = require('../../../tools/approx'), pi = math.pi, complex = math.complex, matrix = math.matrix, + sparse = math.sparse, unit = math.unit, divide = math.divide, atan2 = math.atan2, @@ -16,15 +16,15 @@ var assert = require('assert'), describe('atan2', function() { it('should calculate atan2 correctly', function() { - approx.equal(atan2(0, 0) / pi, 0); - approx.equal(atan2(0, 1) / pi, 0); - approx.equal(atan2(1, 1) / pi, 0.25); - approx.equal(atan2(1, 0) / pi, 0.5); - approx.equal(atan2(1, -1) / pi, 0.75); - approx.equal(atan2(0, -1) / pi, 1); - approx.equal(atan2(-1, -1) / pi, -0.75); - approx.equal(atan2(-1, 0) / pi, -0.5); - approx.equal(atan2(-1, 1) / pi, -0.25); + assert.equal(atan2(0, 0) / pi, 0); + assert.equal(atan2(0, 1) / pi, 0); + assert.equal(atan2(1, 1) / pi, 0.25); + assert.equal(atan2(1, 0) / pi, 0.5); + assert.equal(atan2(1, -1) / pi, 0.75); + assert.equal(atan2(0, -1) / pi, 1); + assert.equal(atan2(-1, -1) / pi, -0.75); + assert.equal(atan2(-1, 0) / pi, -0.5); + assert.equal(atan2(-1, 1) / pi, -0.25); }); it('should calculate atan2 for booleans', function() { @@ -80,32 +80,91 @@ describe('atan2', function() { }); it('should throw an error if called with a string', function() { - assert.throws(function () {atan2('string', 1)}); + assert.throws(function () {atan2('string', 1);}); }); it('should throw an error if called with a unit', function() { - assert.throws(function () {atan2(unit('5cm'), 1)}); + assert.throws(function () {atan2(unit('5cm'), 1);}); + }); + + describe('Array', function () { + + it('should calculate atan2 array - scalar', function () { + assert.deepEqual(divide(atan2(1, [1, -1, 0]), pi), [0.25, 0.75, 0.5]); + assert.deepEqual(divide(atan2([1, -1, 0], 1), pi), [0.25, -0.25, 0]); + }); + + it('should calculate atan2 array - array', function () { + assert.deepEqual(divide(atan2([[1, -1, 0], [1, -1, 0]], [[-1, 0, 1], [1, 1, 1]]), pi), [[0.75, -0.5, 0], [0.25, -0.25, 0]]); + }); + + it('should calculate atan2 array - dense matrix', function () { + assert.deepEqual(divide(atan2([[1, -1, 0], [1, -1, 0]], matrix([[-1, 0, 1], [1, 1, 1]])), pi), matrix([[0.75, -0.5, 0], [0.25, -0.25, 0]])); + }); + + it('should calculate atan2 array - sparse matrix', function () { + assert.deepEqual(divide(atan2([[1, -1, 0], [1, -1, 0]], sparse([[-1, 0, 1], [1, 1, 1]])), pi), matrix([[0.75, -0.5, 0], [0.25, -0.25, 0]])); + }); + }); + + describe('DenseMatrix', function () { + + it('should calculate atan2 dense matrix - scalar', function () { + assert.deepEqual(divide(atan2(1, matrix([1, -1, 0])), pi), matrix([0.25, 0.75, 0.5])); + assert.deepEqual(divide(atan2(matrix([1, -1, 0]), 1), pi), matrix([0.25, -0.25, 0])); + }); + + it('should calculate atan2 dense matrix - array', function () { + assert.deepEqual(divide(atan2(matrix([[1, -1, 0], [1, -1, 0]]), [[-1, 0, 1], [1, 1, 1]]), pi), matrix([[0.75, -0.5, 0], [0.25, -0.25, 0]])); + }); + + it('should calculate atan2 dense matrix - dense matrix', function () { + assert.deepEqual(divide(atan2(matrix([[1, -1, 0], [1, -1, 0]]), matrix([[-1, 0, 1], [1, 1, 1]])), pi), matrix([[0.75, -0.5, 0], [0.25, -0.25, 0]])); + }); + + it('should calculate atan2 dense matrix - sparse matrix', function () { + assert.deepEqual(divide(atan2(matrix([[1, -1, 0], [1, -1, 0]]), sparse([[-1, 0, 1], [1, 1, 1]])), pi), matrix([[0.75, -0.5, 0], [0.25, -0.25, 0]])); + }); + }); + + describe('SparseMatrix', function () { + + it('should calculate atan2 sparse matrix - scalar', function () { + assert.deepEqual(divide(atan2(1, sparse([[1, -1], [0, 1]])), pi), matrix([[0.25, 0.75], [0.5, 0.25]])); + assert.deepEqual(divide(atan2(sparse([[1, -1], [0, 1]]), 1), pi), sparse([[0.25, -0.25], [0, 0.25]])); + }); + + it('should calculate atan2 sparse matrix - array', function () { + assert.deepEqual(divide(atan2(sparse([[1, -1, 0], [1, -1, 0]]), [[-1, 0, 1], [1, 1, 1]]), pi), sparse([[0.75, -0.5, 0], [0.25, -0.25, 0]])); + }); + + it('should calculate atan2 sparse matrix - dense matrix', function () { + assert.deepEqual(divide(atan2(sparse([[1, -1, 0], [1, -1, 0]]), matrix([[-1, 0, 1], [1, 1, 1]])), pi), sparse([[0.75, -0.5, 0], [0.25, -0.25, 0]])); + }); + + it('should calculate atan2 sparse matrix - sparse matrix', function () { + assert.deepEqual(divide(atan2(sparse([[1, -1, 0], [1, -1, 0]]), sparse([[-1, 0, 1], [1, 1, 1]])), pi), sparse([[0.75, -0.5, 0], [0.25, -0.25, 0]])); + }); }); it('should calculate the atan2 element-wise for arrays and matrices', function() { // array, matrix, range - approx.deepEqual(divide(atan2([1,0,-1], [1,0,-1]), pi), [0.25, 0, -0.75]); + approx.deepEqual(divide(atan2([1, 0, -1], [1, 0, -1]), pi), [0.25, 0, -0.75]); approx.deepEqual(divide(atan2( matrix([1,0,-1]), matrix([1,0,-1])), pi), matrix([0.25, 0, -0.75])); - approx.equal(atan2(0, 2) / pi, 0); - approx.equal(atan2(0, -2) / pi, 1); + assert.equal(atan2(0, 2) / pi, 0); + assert.equal(atan2(0, -2) / pi, 1); }); it('should throw an error in case of invalid number of arguments', function() { - assert.throws(function () {atan2(1)}, /TypeError: Too few arguments/); - assert.throws(function () {atan2(1, 2, 3)}, /TypeError: Too many arguments/); + assert.throws(function () {atan2(1);}, /TypeError: Too few arguments/); + assert.throws(function () {atan2(1, 2, 3);}, /TypeError: Too many arguments/); }); it('should LaTeX atan2', function () { var expression = math.parse('atan2(1,1)'); assert.equal(expression.toTex(), '\\mathrm{atan2}\\left(1,1\\right)'); }); - }); diff --git a/test/function/units/to.test.js b/test/function/units/to.test.js index d86acb574..1bc68e4e9 100644 --- a/test/function/units/to.test.js +++ b/test/function/units/to.test.js @@ -1,8 +1,9 @@ var assert = require('assert'), approx = require('../../../tools/approx'), math = require('../../../index'), + matrix = math.matrix, + sparse = math.sparse, Unit = math.type.Unit, - Matrix = math.type.Matrix, unit = math.unit; describe('to', function() { @@ -24,42 +25,47 @@ describe('to', function() { approx.deepEqual(math.to(unit('2 litre'), unit('m3')), e); }); - it('should perform the given unit conversion on each element of an array', function() { - approx.deepEqual(math.to([ - unit('1cm'), - unit('2 inch'), - unit('2km') - ], unit('foot')), [ - new Unit(0.032808, 'foot').to('foot'), - new Unit(0.16667, 'foot').to('foot'), - new Unit(6561.7, 'foot').to('foot') - ]); + describe('Array', function () { + + it('should perform the given unit conversion, array - scalar', function () { + approx.deepEqual(math.to([unit('1cm'), unit('2 inch'), unit('2km')], unit('foot')), [new Unit(0.032808, 'foot').to('foot'), new Unit(0.16667, 'foot').to('foot'), new Unit(6561.7, 'foot').to('foot')]); + approx.deepEqual(math.to(unit('1cm'), [unit('cm'), unit('foot'), unit('km'), unit('m')]), [new Unit(1, 'cm').to('cm'), new Unit(1, 'cm').to('foot'), new Unit(1, 'cm').to('km'), new Unit(1, 'cm').to('m')]); + }); + + it('should perform the given unit conversion, array - array', function () { + approx.deepEqual(math.to([[unit('1cm'), unit('2 inch')], [unit('2km'), unit('1 foot')]], [[unit('foot'), unit('foot')], [unit('cm'), unit('foot')]]), [[unit('1cm').to('foot'), unit('2 inch').to('foot')], [unit('2km').to('cm'), unit('1 foot').to('foot')]]); + }); + + it('should perform the given unit conversion, array - dense matrix', function () { + approx.deepEqual(math.to([[unit('1cm'), unit('2 inch')], [unit('2km'), unit('1 foot')]], matrix([[unit('foot'), unit('foot')], [unit('cm'), unit('foot')]])), matrix([[unit('1cm').to('foot'), unit('2 inch').to('foot')], [unit('2km').to('cm'), unit('1 foot').to('foot')]])); + }); }); + + describe('DenseMatrix', function () { - it('should perform the given unit conversion on each element of a matrix', function() { - var a = math.matrix([ - [unit('1cm'), unit('2cm')], - [unit('3cm'),unit('4cm')] - ]); + it('should perform the given unit conversion, dense matrix - scalar', function () { + approx.deepEqual(math.to(matrix([unit('1cm'), unit('2 inch'), unit('2km')]), unit('foot')), matrix([new Unit(0.032808, 'foot').to('foot'), new Unit(0.16667, 'foot').to('foot'), new Unit(6561.7, 'foot').to('foot')])); + approx.deepEqual(math.to(unit('1cm'), matrix([unit('cm'), unit('foot'), unit('km'), unit('m')])), matrix([new Unit(1, 'cm').to('cm'), new Unit(1, 'cm').to('foot'), new Unit(1, 'cm').to('km'), new Unit(1, 'cm').to('m')])); + }); - var b = math.to(a, unit('mm')); + it('should perform the given unit conversion, dense matrix - array', function () { + approx.deepEqual(math.to(matrix([[unit('1cm'), unit('2 inch')], [unit('2km'), unit('1 foot')]]), [[unit('foot'), unit('foot')], [unit('cm'), unit('foot')]]), matrix([[unit('1cm').to('foot'), unit('2 inch').to('foot')], [unit('2km').to('cm'), unit('1 foot').to('foot')]])); + }); - assert.ok(b instanceof math.type.Matrix); - approx.deepEqual(b, math.matrix([ - [new Unit(10, 'mm').to('mm'), new Unit(20, 'mm').to('mm')], - [new Unit(30, 'mm').to('mm'), new Unit(40, 'mm').to('mm')] - ])); + it('should perform the given unit conversion, dense matrix - dense matrix', function () { + approx.deepEqual(math.to(matrix([[unit('1cm'), unit('2 inch')], [unit('2km'), unit('1 foot')]]), matrix([[unit('foot'), unit('foot')], [unit('cm'), unit('foot')]])), matrix([[unit('1cm').to('foot'), unit('2 inch').to('foot')], [unit('2km').to('cm'), unit('1 foot').to('foot')]])); + }); }); it('should throw an error if converting between incompatible units', function() { - assert.throws(function () {math.to(unit('20 kg'), unit('cm'))}); - assert.throws(function () {math.to(unit('20 celsius'), unit('litre'))}); - assert.throws(function () {math.to(unit('5 cm'), unit('2 m'))}); + assert.throws(function () {math.to(unit('20 kg'), unit('cm'));}); + assert.throws(function () {math.to(unit('20 celsius'), unit('litre'));}); + assert.throws(function () {math.to(unit('5 cm'), unit('2 m'));}); }); it('should throw an error if called with a wrong number of arguments', function() { - assert.throws(function () {math.to(unit('20 kg'))}); - assert.throws(function () {math.to(unit('20 kg'), unit('m'), unit('cm'))}); + assert.throws(function () {math.to(unit('20 kg'));}); + assert.throws(function () {math.to(unit('20 kg'), unit('m'), unit('cm'));}); }); it('should throw an error if called with a non-plain unit', function() { @@ -67,17 +73,16 @@ describe('to', function() { }); it('should throw an error if called with a number', function() { - assert.throws(function () {math.to(5, unit('m'))}, TypeError); - assert.throws(function () {math.to(unit('5cm'), 2)}, /SyntaxError: Unknown unit "2"/); + assert.throws(function () {math.to(5, unit('m'));}, TypeError); + assert.throws(function () {math.to(unit('5cm'), 2);}, /SyntaxError: Unknown unit "2"/); }); it('should throw an error if called with a string', function() { - assert.throws(function () {math.to('5cm', unit('cm'))}, TypeError); + assert.throws(function () {math.to('5cm', unit('cm'));}, TypeError); }); it('should LaTeX to', function () { var expression = math.parse('to(2cm,m)'); assert.equal(expression.toTex(), '\\left(2\\cdot\\mathrm{cm}\\rightarrow\\mathrm{m}\\right)'); }); - }); diff --git a/test/type/matrix/DenseMatrix.test.js b/test/type/matrix/DenseMatrix.test.js index c7379efd1..e63671fcf 100644 --- a/test/type/matrix/DenseMatrix.test.js +++ b/test/type/matrix/DenseMatrix.test.js @@ -36,6 +36,26 @@ describe('DenseMatrix', function() { ]); }); + it('should create a DenseMatrix from an array, number datatype', function () { + var m = new DenseMatrix( + [ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9], + [10, 11, 12] + ], 'number'); + assert.deepEqual(m._size, [4, 3]); + assert.deepEqual( + m._data, + [ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9], + [10, 11, 12] + ]); + assert(m._datatype === 'number'); + }); + it('should create a DenseMatrix an array containing matrices', function () { var m = new DenseMatrix([new DenseMatrix([1,2]), new DenseMatrix([3, 4])]); @@ -55,6 +75,20 @@ describe('DenseMatrix', function() { assert.deepEqual(m1._data, m2._data); }); + it('should create a DenseMatrix from another DenseMatrix, number datatype', function () { + var m1 = new DenseMatrix( + [ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9], + [10, 11, 12] + ], 'number'); + var m2 = new DenseMatrix(m1); + assert.deepEqual(m1._size, m2._size); + assert.deepEqual(m1._data, m2._data); + assert.deepEqual(m1._datatype, m2._datatype); + }); + it('should create a DenseMatrix from a SparseMatrix', function () { var m1 = new SparseMatrix( [ @@ -67,10 +101,28 @@ describe('DenseMatrix', function() { assert.deepEqual(m1.size(), m2.size()); assert.deepEqual(m1.toArray(), m2.toArray()); }); + + it('should create a DenseMatrix from a SparseMatrix, number datatype', function () { + var m1 = new SparseMatrix( + [ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9], + [10, 11, 12] + ], 'number'); + var m2 = new DenseMatrix(m1); + assert.deepEqual(m1.size(), m2.size()); + assert.deepEqual(m1.toArray(), m2.toArray()); + assert.deepEqual(m1._datatype, m2._datatype); + }); it('should throw an error when called without new keyword', function () { assert.throws(function () { DenseMatrix(); }, /Constructor must be called with the new operator/); }); + + it('should throw an error when called with invalid datatype', function () { + assert.throws(function () { new DenseMatrix([], 1); }); + }); }); describe('size', function() { @@ -103,7 +155,19 @@ describe('DenseMatrix', function() { { mathjs: 'DenseMatrix', data: [[1, 2], [3, 4]], - size: [2, 2] + size: [2, 2], + datatype: undefined + }); + }); + + it('should serialize Matrix, number datatype', function() { + assert.deepEqual( + new DenseMatrix([[1,2],[3,4]], 'number').toJSON(), + { + mathjs: 'DenseMatrix', + data: [[1, 2], [3, 4]], + size: [2, 2], + datatype: 'number' }); }); }); @@ -125,6 +189,24 @@ describe('DenseMatrix', function() { assert.strictEqual(m._data[1][0], 3); assert.strictEqual(m._data[1][1], 4); }); + + it('should deserialize Matrix, number datatype', function() { + var json = { + mathjs: 'DenseMatrix', + data: [[1, 2], [3, 4]], + size: [2, 2], + datatype: 'number' + }; + var m = DenseMatrix.fromJSON(json); + assert.ok(m instanceof Matrix); + + assert.deepEqual(m._size, [2, 2]); + assert.strictEqual(m._data[0][0], 1); + assert.strictEqual(m._data[0][1], 2); + assert.strictEqual(m._data[1][0], 3); + assert.strictEqual(m._data[1][1], 4); + assert.strictEqual(m._datatype, 'number'); + }); }); describe('format', function () { diff --git a/test/type/matrix/Spa.test.js b/test/type/matrix/Spa.test.js index 19ba4fc39..8aabc80dc 100644 --- a/test/type/matrix/Spa.test.js +++ b/test/type/matrix/Spa.test.js @@ -6,13 +6,6 @@ describe('Spa', function() { describe('constructor', function() { - it('Should create Spa with initial length', function () { - var spa = new Spa(10); - assert(spa._values !== null); - assert(spa._heap !== null); - assert.equal(spa._values.length, 10); - }); - it('should throw an error when called without new keyword', function () { assert.throws(function () { Spa(); }, /Constructor must be called with the new operator/); }); diff --git a/test/type/matrix/SparseMatrix.test.js b/test/type/matrix/SparseMatrix.test.js index 5f23542c7..96f918f81 100644 --- a/test/type/matrix/SparseMatrix.test.js +++ b/test/type/matrix/SparseMatrix.test.js @@ -3,6 +3,7 @@ var math = require('../../../index'); var index = math.index; var Matrix = math.type.Matrix; var SparseMatrix = math.type.SparseMatrix; +var DenseMatrix = math.type.DenseMatrix; var Complex = math.type.Complex; describe('SparseMatrix', function() { @@ -31,6 +32,24 @@ describe('SparseMatrix', function() { assert.deepEqual(m._values, [10, 3, 3, 9, 7, 8, 4, 8, 8, 7, 7, 9, -2, 5, 9, 2, 3, 13, -1]); assert.deepEqual(m._index, [0, 1, 3, 1, 2, 4, 5, 2, 3, 2, 3, 4, 0, 3, 4, 5, 1, 4, 5]); assert.deepEqual(m._ptr, [0, 3, 7, 9, 12, 16, 19]); + assert(typeof m._datatype === 'undefined'); + }); + + it('should create a Sparse Matrix from an array, number datatype', function () { + var m = new SparseMatrix( + [ + [10, 0, 0, 0, -2, 0], + [3, 9, 0, 0, 0, 3], + [0, 7, 8, 7, 0, 0], + [3, 0, 8, 7, 5, 0], + [0, 8, 0, 9, 9, 13], + [0, 4, 0, 0, 2, -1] + ], 'number'); + assert.deepEqual(m._size, [6, 6]); + assert.deepEqual(m._values, [10, 3, 3, 9, 7, 8, 4, 8, 8, 7, 7, 9, -2, 5, 9, 2, 3, 13, -1]); + assert.deepEqual(m._index, [0, 1, 3, 1, 2, 4, 5, 2, 3, 2, 3, 4, 0, 3, 4, 5, 1, 4, 5]); + assert.deepEqual(m._ptr, [0, 3, 7, 9, 12, 16, 19]); + assert(m._datatype === 'number'); }); it('should create a Sparse Matrix from an array, empty column', function () { @@ -89,6 +108,22 @@ describe('SparseMatrix', function() { assert.deepEqual(m1._ptr, m2._ptr); }); + it('should create a Sparse Matrix from another Sparse Matrix, number datatype', function () { + var m1 = new SparseMatrix( + [ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9], + [10, 11, 12] + ], 'number'); + var m2 = new SparseMatrix(m1); + assert.deepEqual(m1._size, m2._size); + assert.deepEqual(m1._values, m2._values); + assert.deepEqual(m1._index, m2._index); + assert.deepEqual(m1._ptr, m2._ptr); + assert.deepEqual(m1._datatype, m2._datatype); + }); + it('should create a Sparse Matrix from a Dense Matrix', function () { var m1 = math.matrix( [ @@ -102,9 +137,27 @@ describe('SparseMatrix', function() { assert.deepEqual(m1.toArray(), m2.toArray()); }); + it('should create a Sparse Matrix from a Dense Matrix, number datatype', function () { + var m1 = new DenseMatrix( + [ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9], + [10, 11, 12] + ], 'dense', 'number'); + var m2 = new SparseMatrix(m1); + assert.deepEqual(m1.size(), m2.size()); + assert.deepEqual(m1.toArray(), m2.toArray()); + assert.deepEqual(m1._datatype, m2._datatype); + }); + it('should throw an error when called without new keyword', function () { assert.throws(function () { SparseMatrix(); }, /Constructor must be called with the new operator/); }); + + it('should throw an error when called with invalid datatype', function () { + assert.throws(function () { new SparseMatrix([], 1); }); + }); }); describe('size', function() { @@ -134,7 +187,21 @@ describe('SparseMatrix', function() { values: [1, 3, 2, 4], index: [0, 1, 0, 1], ptr: [0, 2, 4], - size: [2, 2] + size: [2, 2], + datatype: undefined + }); + }); + + it('should serialize Matrix, number datatype', function() { + assert.deepEqual( + new SparseMatrix([[1, 2], [3, 4]], 'number').toJSON(), + { + mathjs: 'SparseMatrix', + values: [1, 3, 2, 4], + index: [0, 1, 0, 1], + ptr: [0, 2, 4], + size: [2, 2], + datatype: 'number' }); }); }); @@ -160,6 +227,49 @@ describe('SparseMatrix', function() { [3, 4] ]); }); + + it('should deserialize Matrix, number datatype', function() { + var json = { + mathjs: 'SparseMatrix', + values: [1, 3, 2, 4], + index: [0, 1, 0, 1], + ptr: [0, 2, 4], + size: [2, 2], + datatype: 'number' + }; + var m = SparseMatrix.fromJSON(json); + assert.ok(m instanceof Matrix); + + assert.deepEqual(m._size, [2, 2]); + assert.deepEqual( + m.toArray(), + [ + [1, 2], + [3, 4] + ]); + assert.strictEqual(m._datatype, 'number'); + }); + + it('should deserialize Pattern Matrix', function() { + var json = { + mathjs: 'SparseMatrix', + values: undefined, + index: [0, 1, 2, 0], + ptr: [0, 2, 3, 4], + size: [3, 3] + }; + var m = SparseMatrix.fromJSON(json); + assert.ok(m instanceof Matrix); + + assert.deepEqual(m._size, [3, 3]); + assert.deepEqual( + m.valueOf(), + [ + [1, 0, 1], + [1, 0, 0], + [0, 1, 0] + ]); + }); }); describe('format', function () { @@ -185,6 +295,17 @@ describe('SparseMatrix', function() { ]); assert.equal(m.format(4), 'Sparse Matrix [2 x 2] density: 0.25\n\n (1, 1) ==> 0.3333'); }); + + it('should format pattern matrix', function() { + var m = new SparseMatrix({ + values: undefined, + index: [0, 1, 2, 0], + ptr: [0, 2, 3, 4], + size: [3, 3] + }); + + assert.equal(m.format(3), 'Sparse Matrix [3 x 3] density: 0.444\n\n (0, 0) ==> X\n (1, 0) ==> X\n (2, 1) ==> X\n (0, 2) ==> X'); + }); }); describe('resize', function() { @@ -451,6 +572,16 @@ describe('SparseMatrix', function() { var m = new SparseMatrix([[0, 1], [2, 3]]); assert.throws(function () { m.get([0,2,0,2,0,2]); }, /Dimension mismatch/); }); + + it('should throw an error when invoked on a pattern matrix', function() { + var m = new SparseMatrix({ + values: undefined, + index: [0, 1, 2, 0], + ptr: [0, 2, 3, 4], + size: [3, 3] + }); + assert.throws(function () { m.get([0,1]); }, /Cannot invoke get on a Pattern only matrix/); + }); it('should get matrix element', function () { var m = new SparseMatrix([ @@ -721,6 +852,16 @@ describe('SparseMatrix', function() { [-2, -2, -2, -2, 33] ]); }); + + it('should throw an error when invoked on a pattern matrix', function() { + var m = new SparseMatrix({ + values: undefined, + index: [0, 1, 2, 0], + ptr: [0, 2, 3, 4], + size: [3, 3] + }); + assert.throws(function () { m.set([0,1], 1); }, /Cannot invoke set on a Pattern only matrix/); + }); }); describe('get subset', function() { @@ -775,6 +916,16 @@ describe('SparseMatrix', function() { var m = new SparseMatrix([[1,2,3],[4,5,6]]); assert.throws(function () { m.subset(index([0,2])); }, /Dimension mismatch/); }); + + it('should throw an error when invoked on a pattern matrix', function() { + var m = new SparseMatrix({ + values: undefined, + index: [0, 1, 2, 0], + ptr: [0, 2, 3, 4], + size: [3, 3] + }); + assert.throws(function () { m.subset(index(1, 1)); }, /Cannot invoke subset on a Pattern only matrix/); + }); }); describe('set subset', function() { @@ -985,6 +1136,16 @@ describe('SparseMatrix', function() { it ('should throw an error in case of wrong size of submatrix', function () { assert.throws(function () { new SparseMatrix().subset(index(0), [2,3]); }, /Scalar expected/); }); + + it('should throw an error when invoked on a pattern matrix', function() { + var m = new SparseMatrix({ + values: undefined, + index: [0, 1, 2, 0], + ptr: [0, 2, 3, 4], + size: [3, 3] + }); + assert.throws(function () { m.subset(index([2, 4], [2, 4]), [[1, 2], [3, 4]], -1); }, /Cannot invoke subset on a Pattern only matrix/); + }); }); describe('map', function() { @@ -1079,6 +1240,16 @@ describe('SparseMatrix', function() { [1104, 1115, 1126] ]); }); + + it('should throw an error when invoked on a pattern matrix', function() { + var m = new SparseMatrix({ + values: undefined, + index: [0, 1, 2, 0], + ptr: [0, 2, 3, 4], + size: [3, 3] + }); + assert.throws(function () { m.map(function () {}, m, true); }, /Cannot invoke map on a Pattern only matrix/); + }); }); describe('forEach', function() { @@ -1137,6 +1308,16 @@ describe('SparseMatrix', function() { ); assert.deepEqual(output, [1001, 1104, 1012, 1115, 1023, 1126]); }); + + it('should throw an error when invoked on a pattern matrix', function() { + var m = new SparseMatrix({ + values: undefined, + index: [0, 1, 2, 0], + ptr: [0, 2, 3, 4], + size: [3, 3] + }); + assert.throws(function () { m.forEach(function () {}); }, /Cannot invoke forEach on a Pattern only matrix/); + }); }); describe('clone', function() { @@ -1152,6 +1333,19 @@ describe('SparseMatrix', function() { assert.deepEqual(m1.toArray(), m2.toArray()); }); + + it('should clone pattern matrix', function() { + var m1 = new SparseMatrix({ + values: undefined, + index: [0, 1, 2, 0], + ptr: [0, 2, 3, 4], + size: [3, 3] + }); + + var m2 = m1.clone(); + + assert.deepEqual(m1.toArray(), m2.toArray()); + }); }); describe('toArray', function () { @@ -1841,5 +2035,24 @@ describe('SparseMatrix', function() { [10, 0, 0] ]); }); + + it('should swap rows on a pattern matrix', function() { + var m = new SparseMatrix({ + values: undefined, + index: [0, 1, 2, 0], + ptr: [0, 2, 3, 4], + size: [3, 3] + }); + + m.swapRows(0, 2); + + assert.deepEqual( + m.valueOf(), + [ + [0, 1, 0], + [1, 0, 0], + [1, 0, 1] + ]); + }); }); }); \ No newline at end of file diff --git a/tools/matrixmarket.js b/tools/matrixmarket.js index cc015fbe1..4ccc46aa6 100644 --- a/tools/matrixmarket.js +++ b/tools/matrixmarket.js @@ -195,6 +195,7 @@ var _importFromStream = function (stream, deferred) { var values = []; var index = []; var ptr = []; + var datatype = mm.datatype === 'real' ? 'number' : undefined; // mm data & pointer var d = mm.data; var p = -1; @@ -238,7 +239,8 @@ var _importFromStream = function (stream, deferred) { values: values, index: index, ptr: ptr, - size: [mm.rows, mm.columns] + size: [mm.rows, mm.columns], + datatype: datatype })); break; case 'array':