Getting or setting a subset of a matrix will automatically squeezed/unsqueezed the submatrix

This commit is contained in:
josdejong 2013-09-25 21:59:35 +02:00
parent f68bc8e5f2
commit f48c07bdd8
8 changed files with 45 additions and 27 deletions

View File

@ -4,6 +4,10 @@ https://github.com/josdejong/mathjs
## not yet released, version 0.14.0
*WARNING: version 0.14 is incompatible with previous versions.*
- Getting a subset of a matrix will automatically squeeze the resulting subset,
setting a subset of a matrix will automatically unsqueeze the given subset.
- 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`.

View File

@ -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]]

View File

@ -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]]

View File

@ -16,7 +16,7 @@ module.exports = function (math) {
BlockNode = require('../../expression/node/BlockNode.js'),
ConstantNode = require('../../expression/node/ConstantNode.js'),
FunctionNode = require('../../expression/node/FunctionNode.js'),
MatrixNode = require('../../expression/node/MatrixNode.js'),
ArrayNode = require('../../expression/node/ArrayNode.js'),
OperatorNode = require('../../expression/node/OperatorNode.js'),
ParamsNode = require('../../expression/node/ParamsNode.js'),
RangeNode = require('../../expression/node/RangeNode.js'),
@ -1042,7 +1042,7 @@ module.exports = function (math) {
/**
* parse the matrix
* @param {Scope} scope
* @return {Node} A MatrixNode
* @return {Node} node
* @private
*/
function parseMatrix (scope) {
@ -1098,7 +1098,7 @@ module.exports = function (math) {
}
}
array = new MatrixNode(params);
array = new ArrayNode(params);
}
else {
// 1 dimensional vector
@ -1113,7 +1113,7 @@ module.exports = function (math) {
else {
// this is an empty matrix "[ ]"
getToken();
array = new MatrixNode([]);
array = new ArrayNode([]);
}
// parse parameters
@ -1128,7 +1128,7 @@ module.exports = function (math) {
/**
* Parse a single comma-separated row from a matrix, like 'a, b, c'
* @param {Scope} scope
* @return {MatrixNode} node
* @return {ArrayNode} node
*/
function parseRow (scope) {
var params = [parseAssignment(scope)];
@ -1152,7 +1152,7 @@ module.exports = function (math) {
}
}
return new MatrixNode(params);
return new ArrayNode(params);
}
/**

View File

@ -299,10 +299,14 @@ function _set (matrix, index, submatrix) {
submatrix = submatrix.valueOf();
}
// calculate the size of the submatrix
var subsize = array.size(submatrix);
if (isScalar) {
// set a scalar
// check whether submatrix is no matrix/array
if (array.size(submatrix.valueOf()).length != 0) {
// check whether submatrix is a scalar
if (subsize.length != 0) {
throw new TypeError('Scalar value expected');
}
@ -314,6 +318,12 @@ function _set (matrix, index, submatrix) {
}
else {
// set a submatrix
// unsqueeze the submatrix when needed
for (var i = 0, ii = size.length - subsize.length; i < ii; i++) {
submatrix = [submatrix];
}
var newSize = matrix._size.concat();
_setSubmatrix (matrix._data, newSize, index, 0, submatrix);
if (!object.deepEqual(matrix._size, newSize)) {

View File

@ -172,12 +172,12 @@ describe('parse', function() {
[7,8,9]
])
};
assert.deepEqual(parseAndEval('a(2, :)', scope), new Matrix([[4,5,6]]));
assert.deepEqual(parseAndEval('a(2, :2)', scope), new Matrix([[4,5]]));
assert.deepEqual(parseAndEval('a(2, :end-1)', scope), new Matrix([[4,5]]));
assert.deepEqual(parseAndEval('a(2, 2:)', scope), new Matrix([[5,6]]));
assert.deepEqual(parseAndEval('a(2, 2:3)', scope), new Matrix([[5,6]]));
assert.deepEqual(parseAndEval('a(2, 1:2:3)', scope), new Matrix([[4,6]]));
assert.deepEqual(parseAndEval('a(2, :)', scope), new Matrix([4,5,6]));
assert.deepEqual(parseAndEval('a(2, :2)', scope), new Matrix([4,5]));
assert.deepEqual(parseAndEval('a(2, :end-1)', scope), new Matrix([4,5]));
assert.deepEqual(parseAndEval('a(2, 2:)', scope), new Matrix([5,6]));
assert.deepEqual(parseAndEval('a(2, 2:3)', scope), new Matrix([5,6]));
assert.deepEqual(parseAndEval('a(2, 1:2:3)', scope), new Matrix([4,6]));
assert.deepEqual(parseAndEval('a(:, 2)', scope), new Matrix([[2],[5],[8]]));
assert.deepEqual(parseAndEval('a(:2, 2)', scope), new Matrix([[2],[5]]));
assert.deepEqual(parseAndEval('a(:end-1, 2)', scope), new Matrix([[2],[5]]));
@ -219,7 +219,7 @@ describe('parse', function() {
assert.deepEqual(parseAndEval('a(1:3,1:2)', scope), new Matrix([[100,2],[3,10],[0,12]]));
scope.b = [[1,2],[3,4]];
assert.deepEqual(parseAndEval('b(1,:)', scope), [[1, 2]]); // TODO: matrix should be squeezed
assert.deepEqual(parseAndEval('b(1,:)', scope), [1, 2]);
});
it('should get/set the matrix correctly for 3d matrices', function() {
@ -249,10 +249,10 @@ describe('parse', function() {
]
]);
assert.deepEqual(parseAndEval('size(f)', scope), new Matrix([2,2,2]));
assert.deepEqual(parseAndEval('f(:,:,1)', scope), new Matrix([[[1],[2]],[[3],[4]]])); // TODO: last dimension should be squeezed
assert.deepEqual(parseAndEval('f(:,:,2)', scope), new Matrix([[[5],[6]],[[7],[8]]])); // TODO: last dimension should be squeezed
assert.deepEqual(parseAndEval('f(:,:,1)', scope), new Matrix([[[1],[2]],[[3],[4]]]));
assert.deepEqual(parseAndEval('f(:,:,2)', scope), new Matrix([[[5],[6]],[[7],[8]]]));
assert.deepEqual(parseAndEval('f(:,2,:)', scope), new Matrix([[[2,6]],[[4,8]]]));
assert.deepEqual(parseAndEval('f(2,:,:)', scope), new Matrix([[[3,7],[4,8]]]));
assert.deepEqual(parseAndEval('f(2,:,:)', scope), new Matrix([[3,7],[4,8]]));
parseAndEval('a=diag([1,2,3,4])', scope);
assert.deepEqual(parseAndEval('a(3:end, 3:end)', scope), new Matrix([[3,0],[0,4]]));

View File

@ -49,6 +49,8 @@ describe('subset', function() {
var d = [[1,2], [3,4]];
var g = matrix([[1,2], [3,4]]);
// TODO: test getting subset of an array and matrix
it('should set the right subset of an array', function() {
assert.deepEqual(d, [[1,2], [3,4]]);
assert.deepEqual(subset(d, index([0,2], 1), [[-2],[-4]]), [[1,-2], [3,-4]]);

View File

@ -143,8 +143,8 @@ describe('matrix', function() {
assert.deepEqual(m.size(), [3,3]);
assert.deepEqual(m.subset(index(1,1)), 5);
assert.deepEqual(m.subset(index([0,2],[0,2])).valueOf(), [[1,2],[4,5]]);
assert.deepEqual(m.subset(index(1, [1,3])).valueOf(), [[5,6]]);
assert.deepEqual(m.subset(index(0, [1,3])).valueOf(), [[2,3]]);
assert.deepEqual(m.subset(index(1, [1,3])).valueOf(), [5,6]);
assert.deepEqual(m.subset(index(0, [1,3])).valueOf(), [2,3]);
assert.deepEqual(m.subset(index([1,3], 1)).valueOf(), [[5],[8]]);
assert.deepEqual(m.subset(index([1,3], 2)).valueOf(), [[6],[9]]);
@ -154,8 +154,8 @@ describe('matrix', function() {
assert.deepEqual(m.subset(index([0,2],[0,2],[0,2])).valueOf(), m.valueOf());
assert.deepEqual(m.subset(index(0,0,0)), 1);
assert.deepEqual(m.subset(index(1,1,1)).valueOf(), 8);
assert.deepEqual(m.subset(index(1,1,[0,2])).valueOf(), [[[7,8]]]);
assert.deepEqual(m.subset(index(1,[0,2],1)).valueOf(), [[[6],[8]]]);
assert.deepEqual(m.subset(index(1,1,[0,2])).valueOf(), [7,8]);
assert.deepEqual(m.subset(index(1,[0,2],1)).valueOf(), [[6],[8]]);
});
it('should throw an error if the given subset is invalid', function() {
@ -185,7 +185,9 @@ describe('matrix', function() {
m.resize([3,3]);
assert.deepEqual(m.valueOf(), [[0,0,0],[0,0,0],[0,0,0]]);
m.subset(index([1,3], [1,3]), [[1,2],[3,4]]);
assert.deepEqual(m.valueOf(), [[0,0,0],[0,1,2],[0,3,4]]);
assert.deepEqual(m.valueOf(), [[0,0,0],[0,1,2],[0,3,4]]);
m.subset(index(0, [0,3]), [5,6,7]); // unsqueezes the submatrix
assert.deepEqual(m.valueOf(), [[5,6,7],[0,1,2],[0,3,4]]);
});
it('should resize the matrix if the replacement subset is different size than selected subset', function() {