mirror of
https://github.com/josdejong/mathjs.git
synced 2026-01-25 15:07:57 +00:00
Removed concatenation of nested arrays
This commit is contained in:
parent
625fe4a847
commit
0dfdf3b2a2
@ -2,8 +2,14 @@
|
||||
https://github.com/josdejong/mathjs
|
||||
|
||||
|
||||
## not yet released, version 0.13.1
|
||||
## not yet released, version 0.14.0
|
||||
|
||||
- Removed concatenation of nested arrays in the expression parser.
|
||||
You can now input nested arrays like in JavaScript. Matrices can be
|
||||
concatenated using the function `concat`.
|
||||
- The matrix syntax `[...]` in the expression parser now creates 1 dimensional
|
||||
matrices by default. `math.eval('[1,2,3,4]')` returns a matrix with size `[4]`,
|
||||
`math.eval('[1,2;3,4]')` returns a matrix with size `[2,2]`.
|
||||
- Fixed non working operator `mod` (modulus operator).
|
||||
|
||||
|
||||
|
||||
@ -24,7 +24,7 @@ Powerful and easy to use.
|
||||
|
||||
Math.js can be installed using npm or bower, or by [downloading](http://mathjs.org/#install_or_download) the library.
|
||||
The library can be used in both node.js and in the browser.
|
||||
See the [Getting Start](https://github.com/josdejong/mathjs/blob/master/docs/getting_started.md) for a more detailed tutorial. To install math.js using npm:
|
||||
See the [Getting Started](https://github.com/josdejong/mathjs/blob/master/docs/getting_started.md) for a more detailed tutorial. To install math.js using npm:
|
||||
|
||||
npm install mathjs
|
||||
|
||||
@ -62,9 +62,9 @@ math.select(3)
|
||||
|
||||
## Documentation
|
||||
|
||||
[Getting Started](https://github.com/josdejong/mathjs/blob/master/docs/getting_started.md) •
|
||||
[Examples](https://github.com/josdejong/mathjs/tree/master/examples/) •
|
||||
[Documentation](https://github.com/josdejong/mathjs/blob/master/docs/index.md)
|
||||
- [Getting Started](https://github.com/josdejong/mathjs/blob/master/docs/getting_started.md)
|
||||
- [Examples](https://github.com/josdejong/mathjs/tree/master/examples/)
|
||||
- [Documentation](https://github.com/josdejong/mathjs/blob/master/docs/index.md)
|
||||
|
||||
|
||||
## Build
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mathjs",
|
||||
"version": "0.13.1-SNAPSHOT",
|
||||
"version": "0.14.0-SNAPSHOT",
|
||||
"main": "./dist/math.js",
|
||||
"ignore": [
|
||||
"coverage",
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
# Overview
|
||||
|
||||
The documentation of math.js contains the following pages:
|
||||
# Math.js Documentation
|
||||
|
||||
- [Getting Started](getting_started.md)
|
||||
- [Constants](constants.md)
|
||||
|
||||
@ -41,8 +41,8 @@ parser = math.parser();
|
||||
|
||||
parser.eval('a = [1, 2; 3, 4]'); // Matrix, [[1, 2], [3, 4]]
|
||||
parser.eval('b = zeros(2, 2)'); // Matrix, [[0, 0], [0, 0]]
|
||||
parser.eval('b(1, 1:2) = [5, 6]'); // Matrix, [[5, 6], [0, 0]]
|
||||
parser.eval('b(2, :) = [7, 8]'); // Matrix, [[5, 6], [7, 8]]
|
||||
parser.eval('b(1, 1:2) = [[5, 6]]'); // Matrix, [[5, 6], [0, 0]]
|
||||
parser.eval('b(2, :) = [[7, 8]]'); // Matrix, [[5, 6], [7, 8]]
|
||||
parser.eval('c = a * b'); // Matrix, [[19, 22], [43, 50]]
|
||||
parser.eval('d = c(2, 1)'); // 43
|
||||
parser.eval('e = c(2, 1:end)'); // Matrix, [[43, 50]]
|
||||
|
||||
@ -135,8 +135,8 @@ print(parser.eval('f(2, 3)')); // 8
|
||||
console.log('\nmanipulate matrices');
|
||||
print(parser.eval('k = [1, 2; 3, 4]')); // [[1, 2], [3, 4]]
|
||||
print(parser.eval('l = zeros(2, 2)')); // [[0, 0], [0, 0]]
|
||||
print(parser.eval('l(1, 1:2) = [5, 6]')); // [[5, 6], [0, 0]]
|
||||
print(parser.eval('l(2, :) = [7, 8]')); // [[5, 6], [7, 8]]
|
||||
print(parser.eval('l(1, 1:2) = [[5, 6]]')); // [[5, 6], [0, 0]]
|
||||
print(parser.eval('l(2, :) = [[7, 8]]')); // [[5, 6], [7, 8]]
|
||||
print(parser.eval('m = k * l')); // [[19, 22], [43, 50]]
|
||||
print(parser.eval('n = m(2, 1)')); // 43
|
||||
print(parser.eval('n = m(:, 1)')); // [[19], [43]]
|
||||
|
||||
@ -6,8 +6,8 @@ var Node = require('./Node.js'),
|
||||
|
||||
/**
|
||||
* @constructor MatrixNode
|
||||
* Holds an 2-dimensional array with nodes
|
||||
* @param {Array[]} nodes 2 dimensional array with nodes
|
||||
* Holds an 1-dimensional array with nodes
|
||||
* @param {Array} nodes 1 dimensional array with nodes
|
||||
* @extends {Node}
|
||||
*/
|
||||
function MatrixNode(nodes) {
|
||||
@ -22,26 +22,14 @@ MatrixNode.prototype = new Node();
|
||||
* @override
|
||||
*/
|
||||
MatrixNode.prototype.eval = function() {
|
||||
// evaluate all nodes in the 2d array, and merge the results into a matrix
|
||||
// evaluate all nodes in the array, and merge the results into a matrix
|
||||
var nodes = this.nodes,
|
||||
results = [],
|
||||
mergeNeeded = false;
|
||||
results = [];
|
||||
|
||||
for (var r = 0, rows = nodes.length; r < rows; r++) {
|
||||
var nodes_r = nodes[r];
|
||||
var results_r = [];
|
||||
for (var c = 0, cols = nodes_r.length; c < cols; c++) {
|
||||
var results_rc = nodes_r[c].eval();
|
||||
if (collection.isCollection(results_rc)) {
|
||||
mergeNeeded = true;
|
||||
}
|
||||
results_r[c] = results_rc;
|
||||
}
|
||||
results[r] = results_r;
|
||||
}
|
||||
|
||||
if (mergeNeeded) {
|
||||
results = merge(results);
|
||||
for (var i = 0, ii = nodes.length; i < ii; i++) {
|
||||
var node = nodes[i];
|
||||
var result = node.eval();
|
||||
results[i] = (result instanceof Matrix) ? result.valueOf() : result;
|
||||
}
|
||||
|
||||
return new Matrix(results);
|
||||
@ -77,6 +65,7 @@ MatrixNode.prototype.find = function (filter) {
|
||||
* @param {Array} array Two-dimensional array containing Matrices
|
||||
* @return {Array} merged The merged array (two-dimensional)
|
||||
*/
|
||||
// TODO: cleanup merge function
|
||||
function merge (array) {
|
||||
var merged = [];
|
||||
var rows = array.length;
|
||||
|
||||
@ -1046,7 +1046,7 @@ module.exports = function (math) {
|
||||
* @private
|
||||
*/
|
||||
function parseMatrix (scope) {
|
||||
var array, params, r, c, rows, cols;
|
||||
var array, params, rows, cols;
|
||||
|
||||
if (token == '[') {
|
||||
// matrix [...]
|
||||
@ -1057,92 +1057,58 @@ module.exports = function (math) {
|
||||
getToken();
|
||||
}
|
||||
|
||||
// check if this is an empty matrix "[ ]"
|
||||
if (token != ']') {
|
||||
// this is a non-empty matrix
|
||||
params = [];
|
||||
r = 0;
|
||||
c = 0;
|
||||
var row = parseRow(scope);
|
||||
|
||||
params[0] = [parseAssignment(scope)];
|
||||
if (token == ';') {
|
||||
// 2 dimensional array
|
||||
rows = 1;
|
||||
params = [row];
|
||||
|
||||
// the columns in the matrix are separated by commas, and the rows by dot-comma's
|
||||
while (token == ',' || token == ';') {
|
||||
if (token == ',') {
|
||||
c++;
|
||||
}
|
||||
else {
|
||||
r++;
|
||||
c = 0;
|
||||
params[r] = [];
|
||||
// the rows of the matrix are separated by dot-comma's
|
||||
while (token == ';') {
|
||||
getToken();
|
||||
|
||||
// skip newlines
|
||||
while (token == '\n') {
|
||||
getToken();
|
||||
}
|
||||
|
||||
params[rows] = parseRow(scope);
|
||||
rows++;
|
||||
|
||||
// skip newlines
|
||||
while (token == '\n') {
|
||||
getToken();
|
||||
}
|
||||
}
|
||||
|
||||
// skip newlines
|
||||
if (token != ']') {
|
||||
throw createSyntaxError('End of matrix ] expected');
|
||||
}
|
||||
getToken();
|
||||
while (token == '\n') {
|
||||
getToken();
|
||||
|
||||
// check if the number of columns matches in all rows
|
||||
cols = (params.length > 0) ? params[0].length : 0;
|
||||
for (var r = 1; r < rows; r++) {
|
||||
if (params[r].length != cols) {
|
||||
throw createError('Number of columns must match ' +
|
||||
'(' + params[r].length + ' != ' + cols + ')');
|
||||
}
|
||||
}
|
||||
|
||||
params[r][c] = parseAssignment(scope);
|
||||
|
||||
// skip newlines
|
||||
while (token == '\n') {
|
||||
getToken();
|
||||
array = new MatrixNode(params);
|
||||
}
|
||||
else {
|
||||
// 1 dimensional vector
|
||||
if (token != ']') {
|
||||
throw createSyntaxError('End of matrix ] expected');
|
||||
}
|
||||
getToken();
|
||||
|
||||
array = row;
|
||||
}
|
||||
|
||||
// TODO: spaces as separator for matrix columns
|
||||
/*
|
||||
// the columns in the matrix are separated by commas or spaces,
|
||||
// and the rows by dot-comma's
|
||||
while (token && token != ']') {
|
||||
if (token == ';') {
|
||||
r++;
|
||||
c = 0;
|
||||
params[r] = [];
|
||||
getToken();
|
||||
}
|
||||
else if (token == ',') {
|
||||
c++;
|
||||
getToken();
|
||||
}
|
||||
else {
|
||||
c++;
|
||||
}
|
||||
|
||||
// skip newlines
|
||||
while (token == '\n') {
|
||||
getToken();
|
||||
}
|
||||
|
||||
//TODO: math.eval('[1 -2 3]') is evaluated as '[(1-2) 3]' instead of '[(1) (-2) (3)]'
|
||||
//TODO: '[(1) (-2) (3)]' doesn't work
|
||||
params[r][c] = parseAssignment(scope);
|
||||
|
||||
// skip newlines
|
||||
while (token == '\n') {
|
||||
getToken();
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
rows = params.length;
|
||||
cols = (params.length > 0) ? params[0].length : 0;
|
||||
|
||||
// check if the number of columns matches in all rows
|
||||
for (r = 1; r < rows; r++) {
|
||||
if (params[r].length != cols) {
|
||||
throw createError('Number of columns must match ' +
|
||||
'(' + params[r].length + ' != ' + cols + ')');
|
||||
}
|
||||
}
|
||||
|
||||
if (token != ']') {
|
||||
throw createSyntaxError('End of matrix ] expected');
|
||||
}
|
||||
|
||||
getToken();
|
||||
array = new MatrixNode(params);
|
||||
}
|
||||
else {
|
||||
// this is an empty matrix "[ ]"
|
||||
@ -1159,6 +1125,36 @@ module.exports = function (math) {
|
||||
return parseNumber(scope);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a single comma-separated row from a matrix, like 'a, b, c'
|
||||
* @param {Scope} scope
|
||||
* @return {MatrixNode} node
|
||||
*/
|
||||
function parseRow (scope) {
|
||||
var params = [parseAssignment(scope)];
|
||||
var len = 1;
|
||||
|
||||
while (token == ',') {
|
||||
getToken();
|
||||
|
||||
// skip newlines
|
||||
while (token == '\n') {
|
||||
getToken();
|
||||
}
|
||||
|
||||
// parse expression
|
||||
params[len] = parseAssignment(scope);
|
||||
len++;
|
||||
|
||||
// skip newlines
|
||||
while (token == '\n') {
|
||||
getToken();
|
||||
}
|
||||
}
|
||||
|
||||
return new MatrixNode(params);
|
||||
}
|
||||
|
||||
/**
|
||||
* parse a number
|
||||
* @param {Scope} scope
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mathjs",
|
||||
"version": "0.13.1-SNAPSHOT",
|
||||
"version": "0.14.0-SNAPSHOT",
|
||||
"description": "Math.js is an extensive math library for JavaScript and Node.js. It features real and complex numbers, units, matrices, a large set of mathematical functions, and a flexible expression parser.",
|
||||
"author": "Jos de Jong <wjosdejong@gmail.com>",
|
||||
"contributors": [
|
||||
|
||||
@ -155,7 +155,12 @@ describe('parse', function() {
|
||||
assert.deepEqual(b.size(), [2,2]);
|
||||
assert.deepEqual(b, new Matrix([[5,6],[1,1]]));
|
||||
|
||||
// from 1 to n dimensions
|
||||
assert.deepEqual(parseAndEval('[ ]'), new Matrix([]));
|
||||
assert.deepEqual(parseAndEval('[1,2,3]'), new Matrix([1,2,3]));
|
||||
assert.deepEqual(parseAndEval('[1;2;3]'), new Matrix([[1],[2],[3]]));
|
||||
assert.deepEqual(parseAndEval('[[1,2],[3,4]]'), new Matrix([[1,2],[3,4]]));
|
||||
assert.deepEqual(parseAndEval('[[[1],[2]],[[3],[4]]]'), new Matrix([[[1],[2]],[[3],[4]]]));
|
||||
});
|
||||
|
||||
|
||||
@ -189,15 +194,15 @@ describe('parse', function() {
|
||||
|
||||
assert.deepEqual(parseAndEval('a = []', scope), new Matrix([]));
|
||||
assert.deepEqual(parseAndEval('a(1,3) = 3', scope), new Matrix([[0,0,3]]));
|
||||
assert.deepEqual(parseAndEval('a(2,:) = [4,5,6]', scope), new Matrix([[0,0,3],[4,5,6]]));
|
||||
assert.deepEqual(parseAndEval('a(2,:) = [[4,5,6]]', scope), new Matrix([[0,0,3],[4,5,6]]));
|
||||
|
||||
assert.deepEqual(parseAndEval('a = []', scope), new Matrix([]));
|
||||
assert.deepEqual(parseAndEval('a(3,1) = 3', scope), new Matrix([[0],[0],[3]]));
|
||||
assert.deepEqual(parseAndEval('a(:,2) = [4;5;6]', scope), new Matrix([[0,4],[0,5],[3,6]]));
|
||||
|
||||
assert.deepEqual(parseAndEval('a = []', scope), new Matrix([]));
|
||||
assert.deepEqual(parseAndEval('a(1,1:3) = [1,2,3]', scope), new Matrix([[1,2,3]]));
|
||||
assert.deepEqual(parseAndEval('a(2,:) = [4,5,6]', scope), new Matrix([[1,2,3],[4,5,6]]));
|
||||
assert.deepEqual(parseAndEval('a(1,1:3) = [[1,2,3]]', scope), new Matrix([[1,2,3]]));
|
||||
assert.deepEqual(parseAndEval('a(2,:) = [[4,5,6]]', scope), new Matrix([[1,2,3],[4,5,6]]));
|
||||
});
|
||||
|
||||
it('should get/set the matrix correctly', function() {
|
||||
@ -260,29 +265,33 @@ describe('parse', function() {
|
||||
assert.deepEqual(parseAndEval('a(2:end-1, 2:end-1)', scope), new Matrix([[2,0],[9,9]]));
|
||||
});
|
||||
|
||||
it('should merge nested matrices', function() {
|
||||
var scope = {};
|
||||
parseAndEval('a=[1,2;3,4]', scope);
|
||||
|
||||
});
|
||||
|
||||
it('should parse matrix concatenations', function() {
|
||||
var scope = {};
|
||||
parseAndEval('a=[1,2;3,4]', scope);
|
||||
parseAndEval('b=[5,6;7,8]', scope);
|
||||
assert.deepEqual(parseAndEval('c=[a,b]', scope), new Matrix([[1,2,5,6],[3,4,7,8]]));
|
||||
assert.deepEqual(parseAndEval('c=[a;b]', scope), new Matrix([[1,2],[3,4],[5,6],[7,8]]));
|
||||
assert.deepEqual(parseAndEval('c=[a,b;b,a]', scope), new Matrix([[1,2,5,6],[3,4,7,8],[5,6,1,2],[7,8,3,4]]));
|
||||
assert.deepEqual(parseAndEval('c=[[1,2]; [3,4]]', scope), new Matrix([[1,2],[3,4]]));
|
||||
assert.deepEqual(parseAndEval('c=[1; [2;3]]', scope), new Matrix([[1],[2],[3]]));
|
||||
assert.deepEqual(parseAndEval('c=concat(a,b)', scope), new Matrix([[1,2,5,6],[3,4,7,8]]));
|
||||
assert.deepEqual(parseAndEval('c=concat(a,b,0)', scope), new Matrix([[1,2],[3,4],[5,6],[7,8]]));
|
||||
assert.deepEqual(parseAndEval('c=concat(concat(a,b), concat(b,a), 0)', scope), new Matrix([[1,2,5,6],[3,4,7,8],[5,6,1,2],[7,8,3,4]]));
|
||||
assert.deepEqual(parseAndEval('c=concat([[1,2]], [[3,4]], 0)', scope), new Matrix([[1,2],[3,4]]));
|
||||
assert.deepEqual(parseAndEval('c=concat([[1]], [2;3], 0)', scope), new Matrix([[1],[2],[3]]));
|
||||
assert.deepEqual(parseAndEval('d=1:3', scope), [1,2,3]);
|
||||
assert.deepEqual(parseAndEval('[d,d]', scope), new Matrix([[1,2,3,1,2,3]]));
|
||||
assert.deepEqual(parseAndEval('[d;d]', scope), new Matrix([[1,2,3],[1,2,3]]));
|
||||
assert.deepEqual(parseAndEval('concat(d,d)', scope), [1,2,3,1,2,3]);
|
||||
assert.deepEqual(parseAndEval('e=1+d', scope), [2,3,4]); // e is an Array
|
||||
assert.deepEqual(parseAndEval('size(e)', scope), [3]);
|
||||
assert.deepEqual(parseAndEval('[e,e]', scope), new Matrix([[2,3,4,2,3,4]]));
|
||||
assert.deepEqual(parseAndEval('[e;e]', scope), new Matrix([[2,3,4],[2,3,4]]));
|
||||
assert.deepEqual(parseAndEval('[[],[]]', scope), new Matrix([[]]));
|
||||
assert.deepEqual(parseAndEval('[[],[]]', scope).size(), [1, 0]);
|
||||
assert.deepEqual(parseAndEval('concat(e,e)', scope), [2,3,4,2,3,4]);
|
||||
assert.deepEqual(parseAndEval('[[],[]]', scope), new Matrix([[],[]]));
|
||||
assert.deepEqual(parseAndEval('[[],[]]', scope).size(), [2, 0]);
|
||||
});
|
||||
|
||||
it('should throw an error for invalid matrix concatenations', function() {
|
||||
var scope = {};
|
||||
assert.throws(function () {parseAndEval('c=[a; [1,2,3] ]', scope)});
|
||||
assert.throws(function () {parseAndEval('c=concat(a, [1,2,3])', scope)});
|
||||
});
|
||||
});
|
||||
|
||||
@ -332,7 +341,7 @@ describe('parse', function() {
|
||||
assert.equal(scope.c, 4.5);
|
||||
assert.equal(scope.d, 4.5);
|
||||
assert.equal(scope.e, 4.5);
|
||||
assert.deepEqual(parseAndEval('a = [1,2,f=3]', scope), new Matrix([[1,2,3]]));
|
||||
assert.deepEqual(parseAndEval('a = [1,2,f=3]', scope), new Matrix([1,2,3]));
|
||||
assert.equal(scope.f, 3);
|
||||
assert.equal(parseAndEval('2 + (g = 3 + 4)', scope), 9);
|
||||
assert.equal(scope.g, 7);
|
||||
@ -425,7 +434,7 @@ describe('parse', function() {
|
||||
assert.equal(parseAndEval('4 ./ 2'), 2);
|
||||
assert.equal(parseAndEval('8 ./ 2 / 2'), 2);
|
||||
|
||||
assert.deepEqual(parseAndEval('[1,2,3] ./ [1,2,3]'), new Matrix([[1,1,1]]));
|
||||
assert.deepEqual(parseAndEval('[1,2,3] ./ [1,2,3]'), new Matrix([1,1,1]));
|
||||
});
|
||||
|
||||
it('should parse .*', function() {
|
||||
@ -436,7 +445,7 @@ describe('parse', function() {
|
||||
approx.deepEqual(parseAndEval('8 .* 2 .* 2'), 32);
|
||||
assert.deepEqual(parseAndEval('a=3; a.*4'), [12]);
|
||||
|
||||
assert.deepEqual(parseAndEval('[1,2,3] .* [1,2,3]'), new Matrix([[1,4,9]]));
|
||||
assert.deepEqual(parseAndEval('[1,2,3] .* [1,2,3]'), new Matrix([1,4,9]));
|
||||
});
|
||||
|
||||
it('should parse .^', function() {
|
||||
@ -446,7 +455,7 @@ describe('parse', function() {
|
||||
approx.deepEqual(parseAndEval('-2.^2'), -4); // -(2^2)
|
||||
approx.deepEqual(parseAndEval('2.^3.^4'), 2.41785163922926e+24); // 2^(3^4)
|
||||
|
||||
assert.deepEqual(parseAndEval('[2,3] .^ [2,3]'), new Matrix([[4,27]]));
|
||||
assert.deepEqual(parseAndEval('[2,3] .^ [2,3]'), new Matrix([4,27]));
|
||||
});
|
||||
|
||||
it('should parse ==', function() {
|
||||
@ -640,7 +649,7 @@ describe('parse', function() {
|
||||
it('should correctly stringify a node tree', function() {
|
||||
assert.equal(math.parse('0').toString(), 'ans = 0');
|
||||
assert.equal(math.parse('"hello"').toString(), 'ans = "hello"');
|
||||
assert.equal(math.parse('[1, 2 + 3i, 4]').toString(), 'ans = [[1, 2 + 3i, 4]]');
|
||||
assert.equal(math.parse('[1, 2 + 3i, 4]').toString(), 'ans = [1, 2 + 3i, 4]');
|
||||
});
|
||||
|
||||
it('should support custom node handlers', function() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user