From 952ec790cfd588317dae0e779b315a51e7c1507d Mon Sep 17 00:00:00 2001 From: jos Date: Wed, 22 Apr 2015 22:13:04 +0200 Subject: [PATCH] Refactored concat and flatten to typed-functions --- index.js | 4 +- lib/function/matrix/concat.js | 183 ++++++++++++++------------- lib/function/matrix/flatten.js | 38 +++--- lib/function/matrix/trace.js | 4 +- test/function/matrix/concat.test.js | 2 +- test/function/matrix/flatten.test.js | 6 +- 6 files changed, 116 insertions(+), 121 deletions(-) diff --git a/index.js b/index.js index d20e2d897..f44c4738d 100644 --- a/index.js +++ b/index.js @@ -128,13 +128,13 @@ function create (config) { math.import(require('./lib/function/logical/xor')); // functions - matrix - require('./lib/function/matrix/concat')(math, _config); + math.import(require('./lib/function/matrix/concat')); math.import(require('./lib/function/matrix/cross')); math.import(require('./lib/function/matrix/det')); math.import(require('./lib/function/matrix/diag')); math.import(require('./lib/function/matrix/dot')); math.import(require('./lib/function/matrix/eye')); - require('./lib/function/matrix/flatten')(math, _config); + math.import(require('./lib/function/matrix/flatten')); math.import(require('./lib/function/matrix/inv')); require('./lib/function/matrix/ones')(math, _config); require('./lib/function/matrix/range')(math, _config); diff --git a/lib/function/matrix/concat.js b/lib/function/matrix/concat.js index 16c01091a..8188b1a5e 100644 --- a/lib/function/matrix/concat.js +++ b/lib/function/matrix/concat.js @@ -1,17 +1,13 @@ 'use strict'; -module.exports = function (math) { - var util = require('../../util/index'); +var clone = require('../../util/object').clone; +var isInteger = require('../../util/number').isInteger; +var array = require('../../util/array'); +var IndexError = require('../../error/IndexError'); +var DimensionError = require('../../error/DimensionError'); - var BigNumber = require('decimal.js'); - var Matrix = math.type.Matrix; - var collection = math.collection; - - var object = util.object; - var array = util.array; - var isNumber = util.number.isNumber; - var isInteger = util.number.isInteger; - var isCollection = collection.isCollection; +function factory (type, config, load, typed) { + var matrix = load(require('../construction/matrix')); /** * Concatenate two or more matrices. @@ -41,96 +37,103 @@ module.exports = function (math) { * @param {... Array | Matrix} args Two or more matrices * @return {Array | Matrix} Concatenated matrix */ - math.concat = function concat (args) { - var i, - len = arguments.length, - dim = -1, // zero-based dimension - prevDim, - asMatrix = false, - matrices = []; // contains multi dimensional arrays + return typed('concat', { + // TODO: change signature to '...Array | Matrix, dim?' when supported + '...Array | Matrix | number | BigNumber': function (args) { + var i; + var len = args.length; + var dim = -1; // zero-based dimension + var prevDim; + var asMatrix = false; + var matrices = []; // contains multi dimensional arrays - for (i = 0; i < len; i++) { - var arg = arguments[i]; + for (i = 0; i < len; i++) { + var arg = args[i]; - // test whether we need to return a Matrix (if not we return an Array) - if (arg instanceof Matrix) { - asMatrix = true; - } - - if ((i == len - 1) && (isNumber(arg) || arg instanceof BigNumber)) { - // last argument contains the dimension on which to concatenate - prevDim = dim; - dim = arg.valueOf(); // change bignumber to number - - if (!isInteger(dim)) { - throw new TypeError('Integer number expected for dimension'); + // test whether we need to return a Matrix (if not we return an Array) + if (arg instanceof type.Matrix) { + asMatrix = true; } - if (dim < 0) { - // TODO: would be more clear when throwing a DimensionError here - throw new math.error.IndexError(dim); + if (typeof arg === 'number' || arg instanceof type.BigNumber) { + if (i !== len - 1) { + throw new Error('Dimension must be specified as last argument'); + } + + // last argument contains the dimension on which to concatenate + prevDim = dim; + dim = arg.valueOf(); // change BigNumber to number + + if (!isInteger(dim)) { + throw new TypeError('Integer number expected for dimension'); + } + + if (dim < 0) { + // TODO: would be more clear when throwing a DimensionError here + throw new IndexError(dim); + } + if (i > 0 && dim > prevDim) { + // TODO: would be more clear when throwing a DimensionError here + throw new IndexError(dim, prevDim + 1); + } } - if (i > 0 && dim > prevDim) { - // TODO: would be more clear when throwing a DimensionError here - throw new math.error.IndexError(dim, prevDim + 1); + else { + // this is a matrix or array + var m = clone(arg).valueOf(); + var size = array.size(m); + matrices[i] = m; + prevDim = dim; + dim = size.length - 1; + + // verify whether each of the matrices has the same number of dimensions + if (i > 0 && dim != prevDim) { + throw new DimensionError(prevDim + 1, dim + 1); + } } } - else if (isCollection(arg)) { - // this is a matrix or array - var matrix = object.clone(arg).valueOf(); - var size = array.size(arg.valueOf()); - matrices[i] = matrix; - prevDim = dim; - dim = size.length - 1; - // verify whether each of the matrices has the same number of dimensions - if (i > 0 && dim != prevDim) { - throw new math.error.DimensionError(prevDim + 1, dim + 1); - } - } - else { - throw new math.error.UnsupportedTypeError('concat', math['typeof'](arg)); - } - } - - if (matrices.length == 0) { - throw new SyntaxError('At least one matrix expected'); - } - - var res = matrices.shift(); - while (matrices.length) { - res = _concat(res, matrices.shift(), dim, 0); - } - - return asMatrix ? math.matrix(res) : res; - }; - - /** - * Recursively concatenate two matrices. - * The contents of the matrices is not cloned. - * @param {Array} a Multi dimensional array - * @param {Array} b Multi dimensional array - * @param {Number} concatDim The dimension on which to concatenate (zero-based) - * @param {Number} dim The current dim (zero-based) - * @return {Array} c The concatenated matrix - * @private - */ - function _concat(a, b, concatDim, dim) { - if (dim < concatDim) { - // recurse into next dimension - if (a.length != b.length) { - throw new math.error.DimensionError(a.length, b.length); + if (matrices.length == 0) { + throw new SyntaxError('At least one matrix expected'); } - var c = []; - for (var i = 0; i < a.length; i++) { - c[i] = _concat(a[i], b[i], concatDim, dim + 1); + var res = matrices.shift(); + while (matrices.length) { + res = _concat(res, matrices.shift(), dim, 0); } - return c; + + return asMatrix ? matrix(res) : res; } - else { - // concatenate this dimension - return a.concat(b); + }); +} + +/** + * Recursively concatenate two matrices. + * The contents of the matrices is not cloned. + * @param {Array} a Multi dimensional array + * @param {Array} b Multi dimensional array + * @param {Number} concatDim The dimension on which to concatenate (zero-based) + * @param {Number} dim The current dim (zero-based) + * @return {Array} c The concatenated matrix + * @private + */ +function _concat(a, b, concatDim, dim) { + if (dim < concatDim) { + // recurse into next dimension + if (a.length != b.length) { + throw new DimensionError(a.length, b.length); } + + var c = []; + for (var i = 0; i < a.length; i++) { + c[i] = _concat(a[i], b[i], concatDim, dim + 1); + } + return c; } -}; + else { + // concatenate this dimension + return a.concat(b); + } +} + +exports.name = 'concat'; +exports.factory = factory; diff --git a/lib/function/matrix/flatten.js b/lib/function/matrix/flatten.js index ce73141fa..e79d35f33 100644 --- a/lib/function/matrix/flatten.js +++ b/lib/function/matrix/flatten.js @@ -1,13 +1,10 @@ 'use strict'; -module.exports = function (math, config) { - var util = require('../../util/index'); +var clone = require('../../util/object').clone; +var _flatten = require('../../util/array').flatten; - var Matrix = math.type.Matrix; - - var object = util.object; - var array = util.array; - var isArray = Array.isArray; +function factory (type, config, load, typed) { + var matrix = load(require('../construction/matrix')); /** * Flatten a multi dimensional matrix into a single dimensional matrix. @@ -27,21 +24,18 @@ module.exports = function (math, config) { * @param {Matrix | Array} x Matrix to be flattened * @return {Matrix | Array} Returns the flattened matrix */ - math.flatten = function flatten (x) { - if (arguments.length !== 1) { - throw new math.error.ArgumentsError('flatten', arguments.length, 1); - } + return typed('flatten', { + 'Array': function (x) { + return _flatten(clone(x)); + }, - if (x instanceof Matrix) { - var clone = object.clone(x.toArray()); - var flat = array.flatten(clone); - return math.matrix(flat); + 'Matrix': function (x) { + var flat = _flatten(clone(x.toArray())); + // TODO: return the same matrix type as x + return matrix(flat); } + }); +} - if (isArray(x)) { - return array.flatten(object.clone(x)); - } - - throw new math.error.UnsupportedTypeError('flatten', math['typeof'](x)); - }; -}; +exports.name = 'flatten'; +exports.factory = factory; diff --git a/lib/function/matrix/trace.js b/lib/function/matrix/trace.js index 82ed19b52..b41ae7a85 100644 --- a/lib/function/matrix/trace.js +++ b/lib/function/matrix/trace.js @@ -60,9 +60,7 @@ function factory (type, config, load, typed) { return c; }, - 'any': function (x) { - return clone(x); - } + 'any': clone }); var _denseTrace = function (m) { diff --git a/test/function/matrix/concat.test.js b/test/function/matrix/concat.test.js index d9ce18a12..53e111361 100644 --- a/test/function/matrix/concat.test.js +++ b/test/function/matrix/concat.test.js @@ -94,7 +94,7 @@ describe('concat', function() { }); it('should throw an error in case of invalid type of argument', function() { - assert.throws(function () {math.concat(math.complex(2,3))}, math.error.UnsupportedTypeError); + assert.throws(function () {math.concat(math.complex(2,3))}, /TypeError: Unexpected type of argument/); }); it('should throw an error when called without matrices as argument', function() { diff --git a/test/function/matrix/flatten.test.js b/test/function/matrix/flatten.test.js index 8cad79d45..9c32628e9 100644 --- a/test/function/matrix/flatten.test.js +++ b/test/function/matrix/flatten.test.js @@ -42,9 +42,9 @@ describe('flatten', function() { }); it('should throw an error on invalid arguments', function () { - assert.throws(function () {flatten()}, /ArgumentsError/); - assert.throws(function () {flatten([],2)}, /ArgumentsError/); - assert.throws(function () {flatten("str")}, /TypeError/); + assert.throws(function () {flatten()}, /TypeError: Too few arguments/); + assert.throws(function () {flatten([],2)}, /TypeError: Too many arguments/); + assert.throws(function () {flatten("str")}, /TypeError: Unexpected type of argument/); }); it('should LaTeX flatten', function () {