Intial Commit

This commit is contained in:
valki
2020-10-17 18:42:50 +02:00
commit 664c6d8ca3
5892 changed files with 759183 additions and 0 deletions

25
nodered/rootfs/data/node_modules/mathjs/test/README.md generated vendored Normal file
View File

@@ -0,0 +1,25 @@
## Tests
To execute the tests, install `mocha ` and run the following in the root of
the project:
npm install -g mocha
mocha test --recursive
It's important to run mocha with the `--recursive` flag, as most tests are
located in nested folders.
## Code coverage
To test code coverage of the tests, install `istanbul` and run it:
npm install -g istanbul
istanbul cover _mocha -- test --recursive
Note the underscore before mocha, and the `--` surrounded by spaces after _mocha.
See also https://github.com/gotwarlost/istanbul/issues/44.
To see the results, open the generated report in your browser:
./coverage/lcov-report/index.html

View File

@@ -0,0 +1,78 @@
// test approx itself...
var assert = require('assert'),
approx = require('../tools/approx');
describe('approx', function() {
it('should test equality of positive values', function() {
approx.equal(1/3, 0.33333333);
approx.equal(2, 2.000001);
approx.equal(2, 1.999999);
assert.throws(function () {approx.equal(2, 2.001)}, assert.AssertionError);
assert.throws(function () {approx.equal(2, 1.999)}, assert.AssertionError);
});
it('should test equality of negative values', function() {
approx.equal(-2, -2.000001);
approx.equal(-2, -1.999999);
assert.throws(function () {approx.equal(-2, -2.001)}, assert.AssertionError);
assert.throws(function () {approx.equal(-2, -1.999)}, assert.AssertionError);
});
it('should test equality of very large values', function() {
approx.equal(2e100, 2.000001e100);
approx.equal(2e100, 1.999999e100);
assert.throws(function () {approx.equal(2e100, 2.001e100)}, assert.AssertionError);
assert.throws(function () {approx.equal(2e100, 1.999e100)}, assert.AssertionError);
});
it('should test equality of very small values', function() {
approx.equal(2e-100, 2.000001e-100);
approx.equal(2e-100, 1.999999e-100);
assert.throws(function () {approx.equal(2e-100, 2.001e-100)}, assert.AssertionError);
assert.throws(function () {approx.equal(2e-100, 1.999e-100)}, assert.AssertionError);
});
it('should test equality of NaN numbers', function() {
// NaN values
var a = NaN;
var b = NaN;
approx.equal(a, b);
assert.throws(function () {approx.equal(NaN, 3)}, assert.AssertionError);
assert.throws(function () {approx.equal(NaN, 'nonumber')}, assert.AssertionError);
});
it('should test equality when one of the values is zero', function() {
// zero as one of the two values
approx.equal(0, 1e-15);
approx.equal(1e-15, 0);
assert.throws(function () {approx.equal(0, 0.001)}, assert.AssertionError);
});
it('should test deep equality of arrays and objects', function() {
approx.deepEqual({
a: [1, 2, 3],
b: [{c:4, d:5}]
}, {
a: [1.000001, 1.99999999, 3.000005],
b: [{c:3.999999981, d:5.0000023}]
});
assert.throws(function () {approx.deepEqual({
a: [1, 2, 3],
b: [{c:4, d:5}]
}, {
a: [1.000001, 1.99999999, 3.000005],
b: [{c:3.1, d:5.0000023}]
})}, assert.AssertionError);
assert.throws(function () {approx.deepEqual({
a: [1, 2, 3],
b: [{c:4, d:5}]
}, {
a: [1.001, 1.99999999, 3.000005],
b: [{c:3, d:5.0000023}]
})}, assert.AssertionError);
});
});

View File

@@ -0,0 +1,149 @@
var assert = require('assert'),
math = require('../index'),
approx = require('../tools/approx');
describe('constants', function() {
describe('number', function () {
it('should have pi', function() {
approx.equal(math.pi, 3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664);
approx.equal(math.sin(math.pi / 2), 1);
approx.equal(math.PI, math.pi);
});
it('should have tau', function() {
approx.equal(math.tau, 6.28318530717959);
});
it('should have phi, golden ratio', function() {
approx.equal(math.phi, 1.61803398874989484820458683436563811772030917980576286213545);
});
it('should have e (euler constant)', function() {
approx.equal(math.e, 2.71828182845905);
assert.equal(math.round(math.add(1,math.pow(math.e, math.multiply(math.pi, math.i))), 5), 0);
assert.equal(math.round(math.eval('1+e^(pi*i)'), 5), 0);
});
it('should have LN2', function() {
approx.equal(math.LN2, 0.69314718055994530941723212145817656807550013436025525412068000949339362196969471560586332699641868754200148102057068573);
});
it('should have LN10', function() {
approx.equal(math.LN10, 2.30258509299404568401799145468436420760110148862877297603332790096757260967735248023599720508959829834196778404228624863);
});
it('should have LOG2E', function() {
approx.equal(math.LOG2E, 1.44269504088896340735992468100189213742664595415298593413544940693110921918118507988552662289350634449699751830965254425);
});
it('should have LOG10E', function() {
approx.equal(math.LOG10E, 0.43429448190325182765112891891660508229439700580366656611445378316586464920887077472922494933843174831870610674476630373);
});
it('should have PI', function() {
approx.equal(math.PI, 3.14159265358979);
});
it('should have SQRT1_2', function() {
approx.equal(math.SQRT1_2, 0.70710678118654752440084436210484903928483593768847403658833986899536623923105351942519376716382078636750692311545614851);
});
it('should have SQRT2', function() {
approx.equal(math.SQRT2, 1.41421356237309504880168872420969807856967187537694807317667973799073247846210703885038753432764157273501384623091229702);
});
it('should have Infinity', function() {
assert.strictEqual(math.Infinity, Infinity);
});
it('should have NaN', function() {
assert.ok(isNaN(math.NaN));
});
});
describe('bignumber', function () {
var bigmath = math.create({number: 'BigNumber', precision: 64});
it('should have bignumber pi', function() {
assert.equal(bigmath.pi.toString(), '3.141592653589793238462643383279502884197169399375105820974944592');
});
it('should have bignumber tau', function() {
assert.equal(bigmath.tau.toString(), '6.283185307179586476925286766559005768394338798750211641949889184');
});
it('should have bignumber phi, golden ratio', function() {
assert.equal(bigmath.phi.toString(), '1.618033988749894848204586834365638117720309179805762862135448623');
});
it('should have bignumber e', function() {
assert.equal(bigmath.e.toString(), '2.718281828459045235360287471352662497757247093699959574966967628');
});
it('should have bignumber LN2', function() {
assert.equal(bigmath.LN2.toString(), '0.6931471805599453094172321214581765680755001343602552541206800095');
});
it('should have bignumber LN10', function() {
assert.equal(bigmath.LN10.toString(), '2.302585092994045684017991454684364207601101488628772976033327901');
});
it('should have bignumber LOG2E', function() {
assert.equal(bigmath.LOG2E.toString(), '1.442695040888963407359924681001892137426645954152985934135449407');
});
it('should have bignumber LOG10E', function() {
assert.equal(bigmath.LOG10E.toString(), '0.4342944819032518276511289189166050822943970058036665661144537832');
});
it('should have bignumber PI (upper case)', function() {
assert.equal(bigmath.PI.toString(), '3.141592653589793238462643383279502884197169399375105820974944592');
});
it('should have bignumber SQRT1_2', function() {
assert.equal(bigmath.SQRT1_2.toString(), '0.707106781186547524400844362104849039284835937688474036588339869');
});
it('should have bignumber SQRT2', function() {
assert.equal(bigmath.SQRT2.toString(), '1.414213562373095048801688724209698078569671875376948073176679738');
});
it('should have bignumber Infinity', function() {
assert(bigmath.Infinity instanceof bigmath.type.BigNumber);
assert.strictEqual(bigmath.Infinity.toString(), 'Infinity');
});
it('should have bignumber NaN', function() {
assert(bigmath.NaN instanceof bigmath.type.BigNumber);
assert.equal(bigmath.NaN.toString(), 'NaN');
assert.ok(isNaN(bigmath.NaN));
});
});
it('should have i', function() {
assert.equal(math.i.re, 0);
assert.equal(math.i.im, 1);
assert.deepEqual(math.i, math.complex(0,1));
assert.deepEqual(math.sqrt(-1), math.i);
assert.deepEqual(math.eval('i'), math.complex(0, 1));
});
it('should have true and false', function() {
assert.strictEqual(math.true, true);
assert.strictEqual(math.false, false);
assert.strictEqual(math.eval('true'), true);
assert.strictEqual(math.eval('false'), false);
});
it('should have null', function() {
assert.strictEqual(math['null'], null);
});
it('should have version number', function() {
assert.equal(math.version, require('../package.json').version);
});
});

View File

@@ -0,0 +1,6 @@
var assert = require('assert');
var math = require('../../index');
describe('config', function() {
// TODO: test function config
});

View File

@@ -0,0 +1,271 @@
// test import
var assert = require('assert');
var mathjs = require('../../index');
var approx = require('../../tools/approx');
describe('import', function() {
var math = null;
beforeEach(function() {
math = mathjs.create();
math.import({
myvalue: 42,
hello: function (name) {
return 'hello, ' + name + '!';
}
}, {override: true});
});
afterEach(function() {
math = null;
});
it('should import a custom member', function() {
assert.equal(math.myvalue * 2, 84);
assert.equal(math.hello('user'), 'hello, user!');
});
it('should not override existing functions', function() {
assert.throws(function () {math.import({myvalue: 10})},
/Error: Cannot import "myvalue": already exists/);
assert.equal(math.myvalue, 42);
});
it('should throw no errors when silent:true', function() {
math.import({myvalue: 10}, {silent: true});
assert.strictEqual(math.myvalue, 42);
});
it('should override existing functions if forced', function() {
math.import({myvalue: 10}, {override: true});
assert.strictEqual(math.myvalue, 10);
});
it('should parse the user defined members', function() {
if (math.parser) {
var parser = math.parser();
math.add(math.myvalue, 10);
parser.eval('myvalue + 10'); // 52
parser.eval('hello("user")'); // 'hello, user!'
}
});
var getSize = function (array) {
return array.length;
};
it('shouldn\'t wrap custom functions by default', function () {
math.import({ getSizeNotWrapped: getSize });
assert.strictEqual(math.getSizeNotWrapped([1,2,3]), 3);
assert.strictEqual(math.getSizeNotWrapped(math.matrix([1,2,3])), undefined);
});
it('should wrap custom functions if wrap = true', function () {
math.import({ getSizeWrapped: getSize }, { wrap: true});
assert.strictEqual(math.getSizeWrapped([1,2,3]), 3);
assert.strictEqual(math.getSizeWrapped(math.matrix([1,2,3])), 3);
});
it('wrapped imported functions should accept undefined and null', function () {
math.import({
isNull: function (obj) {
return obj === null;
}
}, { wrap: true });
assert.equal(math.isNull(null), true);
assert.equal(math.isNull(0), false);
math.import({
isUndefined: function (obj) {
return obj === undefined;
}
}, { wrap: true });
assert.equal(math.isUndefined(undefined), true);
assert.equal(math.isUndefined(0), false);
assert.equal(math.isUndefined(null), false);
});
it('should throw an error in case of wrong number of arguments', function () {
assert.throws (function () {math.import()}, /ArgumentsError/);
assert.throws (function () {math.import('', {}, 3)}, /ArgumentsError/);
});
it('should throw an error in case of wrong type of arguments', function () {
assert.throws(function () {math.import(2)}, /TypeError: Factory, Object, or Array expected/);
assert.throws(function () {math.import(function () {})}, /TypeError: Factory, Object, or Array expected/);
});
it('should ignore properties on Object', function () {
Object.prototype.foo = 'bar';
math.import({bar: 456});
assert(!math.hasOwnProperty('foo'));
assert(math.hasOwnProperty('bar'));
delete Object.prototype.foo;
});
it('should return the imported object', function () {
math.import({a: 24});
assert.deepEqual(math.a, 24);
math.import({pi: 24}, {silent: true});
approx.equal(math.pi, Math.PI); // pi was ignored
});
it('should import a boolean', function () {
math.import({a: true});
assert.strictEqual(math.a, true);
});
it('should merge typed functions with the same name', function () {
math.import({
'foo': math.typed('foo', {
'number': function (x) {
return 'foo(number)';
}
})
});
math.import({
'foo': math.typed('foo', {
'string': function (x) {
return 'foo(string)';
}
})
});
assert.deepEqual(Object.keys(math.foo.signatures).sort(), ['number', 'string']);
assert.equal(math.foo(2), 'foo(number)');
assert.equal(math.foo('bar'), 'foo(string)');
assert.throws(function () {
math.foo(new Date())
}, /TypeError: Unexpected type of argument in function foo/);
});
it('should override existing typed functions', function () {
math.import({
'foo': math.typed('foo', {
'Date': function (x) {
return 'foo(Date)';
}
})
});
assert.equal(math.foo(new Date()), 'foo(Date)');
math.import({
'foo': math.typed('foo', {
'string': function (x) {
return 'foo(string)';
}
})
}, {override: true});
assert.deepEqual(Object.keys(math.foo.signatures).sort(), ['string']);
assert.equal(math.foo('bar'), 'foo(string)');
assert.throws(function () {
math.foo(new Date())
}, /TypeError: Unexpected type of argument in function foo/);
assert.throws(function () {
math.foo(new Date())
}, /TypeError: Unexpected type of argument in function foo/);
});
it('should merge typed functions coming from a factory', function () {
math.import({
'foo': math.typed('foo', {
'number': function (x) {
return 'foo(number)';
}
})
});
math.import({
'name': 'foo',
'factory': function () {
return math.typed('foo', {
'string': function (x) {
return 'foo(string)';
}
})
}
});
assert.deepEqual(Object.keys(math.foo.signatures).sort(), ['number', 'string']);
assert.equal(math.foo(2), 'foo(number)');
assert.equal(math.foo('bar'), 'foo(string)');
assert.throws(function () {
math.foo(new Date())
}, /TypeError: Unexpected type of argument in function foo/);
});
it('should import a boolean', function () {
math.import({a: true});
assert.strictEqual(math.a, true);
});
it('should import a function with transform', function() {
function foo (text) {
return text.toLowerCase();
}
foo.transform = function foo(text) {
return text.toUpperCase();
};
math.import({foo: foo});
assert(math.hasOwnProperty('foo'));
assert.strictEqual(math.foo, foo);
assert(math.expression.transform.hasOwnProperty('foo'));
assert.strictEqual(math.expression.transform.foo, foo.transform);
});
it('should throw an error when a factory function has a transform', function() {
assert.throws(function () {
math.import({
name: 'foo2',
factory: function () {
var fn = function () {};
fn.transform = function () {};
return fn;
}
});
math.foo2(); // as soon as we use it, it will resolve the factory function
}, /Transforms cannot be attached to factory functions/);
});
it.skip('should import a factory with name', function () {
// TODO: unit test importing a factory
});
it.skip('should import a factory with path', function () {
// TODO: unit test importing a factory
});
it.skip('should import a factory without name', function () {
// TODO: unit test importing a factory
});
it.skip('should pass the namespace to a factory function', function () {
// TODO: unit test importing a factory
});
it.skip('should import an Array', function () {
// TODO: unit test importing an Array containing stuff
});
it('should LaTeX import', function () {
var expression = math.parse('import(object)');
assert.equal(expression.toTex(), '\\mathrm{import}\\left( object\\right)');
});
});

View File

@@ -0,0 +1 @@
// TODO: test core

View File

@@ -0,0 +1,14 @@
// test error messages for deprecated functions
var assert = require('assert');
var math = require('../index');
describe('deprecated stuff', function() {
it('should throw a deprecation error when using UpdateNode', function () {
assert.throws(function () {
new math.expression.node.UpdateNode();
}, /UpdateNode is deprecated/);
})
});

View File

@@ -0,0 +1,34 @@
var assert = require('assert'),
ArgumentsError = require('../../lib/error/ArgumentsError');
describe('ArgumentsError', function () {
it('should construct an ArgumentsError without max', function () {
var err = new ArgumentsError('myfunction', 1, 2);
assert(err instanceof Error);
assert(err instanceof ArgumentsError);
assert.equal(err.fn, 'myfunction');
assert.equal(err.count, 1);
assert.equal(err.min, 2);
assert.equal(err.max, undefined);
assert.equal(err.toString(), 'ArgumentsError: Wrong number of arguments in function myfunction (1 provided, 2 expected)');
});
it('should construct an ArgumentsError with max', function () {
var err = new ArgumentsError('myfunction', 1, 2, 3);
assert(err instanceof Error);
assert(err instanceof ArgumentsError);
assert.equal(err.fn, 'myfunction');
assert.equal(err.count, 1);
assert.equal(err.min, 2);
assert.equal(err.max, 3);
assert.equal(err.toString(), 'ArgumentsError: Wrong number of arguments in function myfunction (1 provided, 2-3 expected)');
});
it('should throw an error when operator new is missing', function () {
assert.throws(function () {
ArgumentsError();
}, SyntaxError);
});
});

View File

@@ -0,0 +1,54 @@
var assert = require('assert'),
DimensionError = require('../../lib/error/DimensionError');
describe('DimensionError', function () {
it('should construct a DimensionError with numbers', function () {
var err = new DimensionError(3, 5);
assert(err instanceof Error);
assert(err instanceof RangeError);
assert(err instanceof DimensionError);
assert.equal(err.actual, 3);
assert.equal(err.expected, 5);
assert.equal(err.relation, undefined);
assert.equal(err.toString(), 'DimensionError: Dimension mismatch (3 != 5)');
});
it('should construct a DimensionError with numbers and a custom relation', function () {
var err = new DimensionError(3, 5, '<');
assert(err instanceof Error);
assert(err instanceof RangeError);
assert(err instanceof DimensionError);
assert.equal(err.actual, 3);
assert.equal(err.expected, 5);
assert.equal(err.relation, '<');
assert.equal(err.toString(), 'DimensionError: Dimension mismatch (3 < 5)');
});
it('should construct a DimensionError with arrays', function () {
var err = new DimensionError([2,3], [1,3]);
assert(err instanceof Error);
assert(err instanceof RangeError);
assert(err instanceof DimensionError);
assert.deepEqual(err.actual, [2,3]);
assert.deepEqual(err.expected, [1,3]);
assert.equal(err.relation, undefined);
assert.equal(err.toString(), 'DimensionError: Dimension mismatch ([2, 3] != [1, 3])');
});
it('should construct a DimensionError with arrays and a custom relation', function () {
var err = new DimensionError([2,3], [1,3], '<');
assert(err instanceof Error);
assert(err instanceof RangeError);
assert(err instanceof DimensionError);
assert.deepEqual(err.actual, [2,3]);
assert.deepEqual(err.expected, [1,3]);
assert.equal(err.relation, '<');
assert.equal(err.toString(), 'DimensionError: Dimension mismatch ([2, 3] < [1, 3])');
});
it('should throw an error when operator new is missing', function () {
assert.throws(function () {DimensionError(3, 5);}, SyntaxError);
});
});

View File

@@ -0,0 +1,66 @@
var assert = require('assert'),
IndexError = require('../../lib/error/IndexError');
describe('IndexError', function () {
it('should construct an IndexError without min and max', function () {
var err = new IndexError(5);
assert(err instanceof Error);
assert(err instanceof RangeError);
assert(err instanceof IndexError);
assert.equal(err.index, 5);
assert.equal(err.min, 0);
assert.equal(err.max, undefined);
assert.equal(err.toString(), 'IndexError: Index out of range (5)');
});
it('should construct an IndexError without min and max (2)', function () {
var err = new IndexError(-5);
assert(err instanceof Error);
assert(err instanceof RangeError);
assert(err instanceof IndexError);
assert.equal(err.index, -5);
assert.equal(err.min, 0);
assert.equal(err.max, undefined);
assert.equal(err.toString(), 'IndexError: Index out of range (-5 < 0)');
});
it('should construct an IndexError with max', function () {
var err = new IndexError(5, 3);
assert(err instanceof Error);
assert(err instanceof RangeError);
assert(err instanceof IndexError);
assert.equal(err.index, 5);
assert.equal(err.min, 0);
assert.equal(err.max, 3);
assert.equal(err.toString(), 'IndexError: Index out of range (5 > 2)');
});
it('should construct an IndexError with min and max', function () {
var err = new IndexError(0, 2, 5);
assert(err instanceof Error);
assert(err instanceof RangeError);
assert(err instanceof IndexError);
assert.equal(err.index, 0);
assert.equal(err.min, 2);
assert.equal(err.max, 5);
assert.equal(err.toString(), 'IndexError: Index out of range (0 < 2)');
});
it('should construct an IndexError with min and max', function () {
var err = new IndexError(6, 1, 4);
assert(err instanceof Error);
assert(err instanceof RangeError);
assert(err instanceof IndexError);
assert.equal(err.index, 6);
assert.equal(err.min, 1);
assert.equal(err.max, 4);
assert.equal(err.toString(), 'IndexError: Index out of range (6 > 3)');
});
it('should throw an error when constructed without new operator', function() {
assert.throws(function () {
IndexError(5);
});
});
});

View File

@@ -0,0 +1,13 @@
var assert = require('assert');
var error = require('../../lib/error/index');
describe('index.js', function () {
it('should contain error factory functions', function () {
assert(Array.isArray(error));
assert(error[0].name, 'ArgumentsError');
assert(error[1].name, 'DimensionError');
assert(error[2].name, 'IndexError');
});
});

View File

@@ -0,0 +1,187 @@
// test Help
var assert = require('assert');
var math = require('../../index');
var Help = math.type.Help;
describe('help', function() {
var doc = {
'name': 'add',
'category': 'Operators',
'syntax': [
'x + y',
'add(x, y)'
],
'description': 'Add two values.',
'examples': [
'a = 2.1 + 3.6',
'a - 3.6'
],
'seealso': [
'subtract'
]
};
it('should generate the help for a function', function() {
var help = new Help(doc);
assert(help instanceof Help);
assert.deepEqual(help.doc.name, 'add');
assert.deepEqual(help.doc, doc);
});
it('should throw an error when constructed without new operator', function() {
assert.throws(function () {
Help(math.expression.docs.sin);
}, /Constructor must be called with the new operator/)
});
it('should throw an error when constructed without doc argument', function() {
assert.throws(function () {
new Help();
}, /Argument "doc" missing/)
});
it('should have a property isHelp', function () {
var a = new Help(doc);
assert.strictEqual(a.isHelp, true);
});
it('should have a property type', function () {
var a = new Help(doc);
assert.strictEqual(a.type, 'Help');
});
it('should stringify a help', function() {
var help = new Help(doc);
assert.equal(help.toString(),
'\nName: add\n' +
'\n'+
'Category: Operators\n' +
'\n' +
'Description:\n' +
' Add two values.\n' +
'\n' +
'Syntax:\n' +
' x + y\n' +
' add(x, y)\n' +
'\n' +
'Examples:\n' +
' a = 2.1 + 3.6\n' +
' 5.7\n' +
' a - 3.6\n' +
' 2.1\n' +
'\n' +
'See also: subtract\n');
});
it('should stringify a help with empty doc', function() {
var help = new Help({});
assert.equal(help.toString(), '\n');
});
it('should stringify a doc with empty example', function() {
var help = new Help({
'name': 'add',
'examples': [
'2 + 3',
''
]
});
assert.equal(help.toString(),
'\nName: add\n' +
'\n'+
'Examples:\n' +
' 2 + 3\n' +
' 5\n' +
' \n' +
'\n');
});
it('should stringify a doc with example throwing an error', function() {
var help = new Help({
'name': 'add',
'examples': [
'2 ^^ 3'
]
});
assert.equal(help.toString(),
'\nName: add\n' +
'\n'+
'Examples:\n' +
' 2 ^^ 3\n' +
' SyntaxError: Value expected (char 4)\n' +
'\n');
});
it('should return string representation on valueOf', function() {
var help = new Help({
'name': 'add',
'examples': [
'2 ^^ 3'
]
});
assert.strictEqual(help.valueOf(),
'\nName: add\n' +
'\n'+
'Examples:\n' +
' 2 ^^ 3\n' +
' SyntaxError: Value expected (char 4)\n' +
'\n');
});
it('should export doc to JSON', function() {
var help = new Help(doc);
var json = help.toJSON();
assert.deepEqual(json, {
'mathjs': 'Help',
'name': 'add',
'category': 'Operators',
'syntax': [
'x + y',
'add(x, y)'
],
'description': 'Add two values.',
'examples': [
'a = 2.1 + 3.6',
'a - 3.6'
],
'seealso': [
'subtract'
]
});
json.name = 'foo'; // this should not alter the original doc
json.examples.push('2 + 3'); // this should not alter the original doc
assert.equal(doc.name, 'add');
assert.notEqual(json.examples.length, doc.examples.length);
});
it('should instantiate Help from json using fromJSON', function() {
var doc = {
'name': 'add',
'category': 'Operators',
'syntax': [
'x + y',
'add(x, y)'
],
'description': 'Add two values.',
'examples': [
'a = 2.1 + 3.6',
'a - 3.6'
],
'seealso': [
'subtract'
]
};
var json = Object.create(doc);
json['mathjs'] = 'Help';
var help = Help.fromJSON(json);
assert(help instanceof Help);
assert.deepEqual(doc, help.doc);
});
});

View File

@@ -0,0 +1,152 @@
// test parser
var assert = require('assert'),
approx = require('../../tools/approx'),
math = require('../../index'),
Parser = math.expression.Parser;
describe('parser', function() {
it ('should create a parser', function () {
var parser = new Parser();
assert.ok(parser instanceof Parser);
});
it('should have a property isParser', function () {
var a = new Parser();
assert.strictEqual(a.isParser, true);
});
it('should have a property type', function () {
var a = new Parser();
assert.strictEqual(a.type, 'Parser');
});
it ('should throw an error when using deprecated function parse', function () {
var parser = new Parser();
assert.throws(function () {parser.parse('2 + 3');}, /is deprecated/);
});
it ('should throw an error when using deprecated function compile', function () {
var parser = new Parser();
assert.throws(function () {parser.compile('2 + 3');}, /is deprecated/);
});
it ('should evaluate an expression', function () {
var parser = new Parser();
var result = parser.eval('2 + 3');
assert.equal(result, 5);
});
it ('should get variables from the parsers namespace ', function () {
var parser = new Parser();
parser.eval('a = 3');
parser.eval('b = a + 2');
assert.equal(parser.eval('a'), 3);
assert.equal(parser.eval('b'), 5);
assert.equal(parser.get('a'), 3);
assert.equal(parser.get('b'), 5);
});
it ('should get all variables from the parsers namespace ', function () {
var parser = new Parser();
parser.eval('a = 3');
parser.eval('b = a + 2');
assert.deepEqual(parser.getAll(), {a: 3, b: 5});
parser.remove('a');
assert.deepEqual(parser.getAll(), {b: 5});
});
it ('should return null when getting a non existing variable', function () {
var parser = new Parser();
assert.equal(parser.get('non_existing_variable'), null);
});
it ('should set variables in the parsers namespace ', function () {
var parser = new Parser();
assert.equal(parser.set('a', 3), 3);
assert.equal(parser.eval('a'), 3);
assert.equal(parser.eval('a + 2'), 5);
// adjust variable
assert.equal(parser.eval('a = a + 2'), 5);
assert.equal(parser.eval('a'), 5);
assert.equal(parser.get('a'), 5);
assert.equal(parser.set('a', parser.get('a') - 4), 1);
assert.equal(parser.eval('a'), 1);
});
it ('should remove a variable from the parsers namespace ', function () {
var parser = new Parser();
assert.equal(parser.set('qq', 3), 3);
assert.equal(parser.eval('qq'), 3);
assert.equal(parser.get('qq'), 3);
parser.remove('qq');
assert.equal(parser.get('qq'), null);
assert.throws(function () {parser.eval('qq')});
assert.equal(parser.eval('ww = 5'), 5);
assert.equal(parser.get('ww'), 5);
parser.remove('ww');
assert.equal(parser.get('ww'), null);
assert.throws(function () {parser.eval('ww')});
});
it ('should clear the parsers namespace ', function () {
var parser = new Parser();
assert.equal(parser.eval('xx = yy = zz = 5'), 5);
assert.equal(parser.set('pi', 'oops'), 'oops');
assert.equal(parser.get('xx'), 5);
assert.equal(parser.get('yy'), 5);
assert.equal(parser.get('zz'), 5);
assert.equal(parser.get('pi'), 'oops');
assert.equal(parser.eval('xx'), 5);
assert.equal(parser.eval('yy'), 5);
assert.equal(parser.eval('zz'), 5);
assert.equal(parser.eval('pi'), 'oops');
parser.clear();
assert.equal(parser.get('xx'), null);
assert.equal(parser.get('yy'), null);
assert.equal(parser.get('zz'), null);
approx.equal(parser.get('pi'), null);
assert.throws(function () {parser.eval('xx')});
assert.throws(function () {parser.eval('yy')});
assert.throws(function () {parser.eval('zz')});
assert.equal(parser.eval('pi'), Math.PI);
});
it ('should not clear inherited properties', function () {
var parser = new Parser();
Object.prototype.foo = 'bar';
parser.clear();
assert.equal(parser.get('foo'), 'bar');
delete Object.prototype.foo;
});
it ('should throw an exception when creating a parser without new', function () {
assert.throws(function () {Parser()}, /Constructor must be called with the new operator/);
});
});

View File

@@ -0,0 +1,37 @@
// test compile
var assert = require('assert');
var math = require('../../../index');
describe('compile', function() {
it('should compile an expression', function() {
var code = math.compile('(5+3)/4');
assert.ok(code instanceof Object);
assert.ok(code.eval instanceof Function);
assert.equal(code.eval(), 2);
});
it('should parse multiple expressions', function() {
var codes = math.compile(['2+3', '4+5']);
assert.ok(Array.isArray(codes));
assert.equal(codes.length, 2);
assert.equal(codes[0].eval(), 5);
assert.equal(codes[1].eval(), 9);
});
it('should throw an error on wrong number of arguments', function() {
assert.throws(function () {math.compile()}, /TypeError: Too few arguments/);
assert.throws(function () {math.compile('2+3', '3+4')}, /TypeError: Too many arguments/);
});
it('should throw an error on wrong type of argument', function() {
assert.throws(function () {math.compile(math.complex(2, 3))}, TypeError);
});
it('should LaTeX compile', function () {
var expression = math.parse('compile(1)');
assert.equal(expression.toTex(), '\\mathrm{compile}\\left(1\\right)');
});
});

View File

@@ -0,0 +1,79 @@
// test eval
var assert = require('assert');
var approx = require('../../../tools/approx');
var math = require('../../../index');
var Complex = math.type.Complex;
var Matrix = math.type.Matrix;
var Unit = math.type.Unit;
var ResultSet = math.type.ResultSet;
describe('eval', function() {
it('should evaluate expressions', function() {
approx.equal(math.eval('(2+3)/4'), 1.25);
assert.deepEqual(math.eval('sqrt(-4)'), new Complex(0, 2));
});
it('should eval a list of expressions', function() {
assert.deepEqual(math.eval(['1+2', '3+4', '5+6']), [3, 7, 11]);
assert.deepEqual(math.eval(['a=3', 'b=4', 'a*b']), [3, 4, 12]);
assert.deepEqual(math.eval(math.matrix(['a=3', 'b=4', 'a*b'])), math.matrix([3, 4, 12]));
assert.deepEqual(math.eval(['a=3', 'b=4', 'a*b']), [3, 4, 12]);
});
it('should eval a series of expressions', function() {
assert.deepEqual(math.eval('a=3\nb=4\na*b'), new ResultSet([3, 4, 12]));
assert.deepEqual(math.eval('f(x) = a * x; a=2; f(4)'), new ResultSet([8]));
assert.deepEqual(math.eval('b = 43; b * 4'), new ResultSet([172]));
});
it('should throw an error if wrong number of arguments', function() {
assert.throws(function () {math.eval()}, /TypeError: Too few arguments/);
assert.throws(function () {math.eval('', {}, 3)}, /TypeError: Too many arguments/);
});
it('should throw an error with a unit', function() {
assert.throws(function () {math.eval(new Unit(5, 'cm'))}, /TypeError: Unexpected type of argument/);
});
it('should throw an error with a complex number', function() {
assert.throws(function () {math.eval(new Complex(2,3))}, /TypeError: Unexpected type of argument/);
});
it('should throw an error with a boolean', function() {
assert.throws(function () {math.eval(true)}, TypeError);
});
it('should handle the given scope', function() {
var scope = {
a: 3,
b: 4
};
assert.deepEqual(math.eval('a*b', scope), 12);
assert.deepEqual(math.eval('c=5', scope), 5);
assert.deepEqual(math.format(math.eval('f(x) = x^a', scope)), 'f(x)');
assert.deepEqual(Object.keys(scope).length, 4);
assert.deepEqual(scope.a, 3);
assert.deepEqual(scope.b, 4);
assert.deepEqual(scope.c, 5);
assert.deepEqual(typeof scope.f, 'function');
assert.equal(scope.f(3), 27);
scope.a = 2;
assert.equal(scope.f(3), 9);
scope.hello = function (name) {
return 'hello, ' + name + '!';
};
assert.deepEqual(math.eval('hello("jos")', scope), 'hello, jos!');
});
it('should LaTeX eval', function () {
var expr1 = math.parse('eval(expr)');
var expr2 = math.parse('eval(expr,scope)');
assert.equal(expr1.toTex(), '\\mathrm{eval}\\left( expr\\right)');
assert.equal(expr2.toTex(), '\\mathrm{eval}\\left( expr, scope\\right)');
});
});

View File

@@ -0,0 +1,60 @@
var assert = require('assert'),
error = require('../../../lib/error/index'),
math = require('../../../index');
describe('help', function() {
it('should find documentation for a function by its name', function() {
var help = math.help('sin');
assert.ok(help instanceof math.type.Help);
assert.deepEqual(help.doc, math.expression.docs.sin);
});
it('should find documentation for a function by the function itself', function() {
var help = math.help(math.sin);
assert.ok(help instanceof math.type.Help);
assert.deepEqual(help.doc, math.expression.docs.sin);
});
it('should throw an error on wrong number of arguments', function() {
assert.throws(function () {math.help()}, /TypeError: Too few arguments/);
assert.throws(function () {math.help('sin', 2)}, /TypeError: Too many arguments/);
});
it('should find help from a function name', function() {
var help = math.help('sin');
assert(help instanceof math.type.Help);
assert.equal(help.doc.name, 'sin');
});
it('should find help from a function', function() {
var help = math.help(math.sin);
assert(help instanceof math.type.Help);
assert.equal(help.doc.name, 'sin');
});
it('should find help from a constant name', function() {
var help = math.help('pi');
assert(help instanceof math.type.Help);
assert.equal(help.doc.name, 'pi');
});
it('should find help from a constant', function() {
var help = math.help(math.pi);
assert(help instanceof math.type.Help);
assert.equal(help.doc.name, 'pi');
});
it('should throw an error when no help is found', function() {
// assert.throws(function () {math.help(undefined)}, /No documentation found/);
assert.throws(function () {math.help(new Date())}, /No documentation found/);
assert.throws(function () {math.help('nonExistingFunction')}, /No documentation found/);
assert.throws(function () {math.help('parse')}, /No documentation found/);
});
it('should LaTeX help', function () {
var expression = math.parse('help(parse)');
assert.equal(expression.toTex(), '\\mathrm{help}\\left( parse\\right)');
});
});

View File

@@ -0,0 +1,31 @@
// test parse
var assert = require('assert');
var error = require('../../../lib/error/index');
var math = require('../../../index');
var Node = math.expression.node.Node;
describe('parse', function() {
it('should parse an expression', function() {
var node = math.parse('(5+3)/4');
assert.ok(node instanceof Node);
assert.equal(node.compile().eval(), 2);
});
it('should parse multiple expressions', function() {
var nodes = math.parse(['2+3', '4+5']);
assert.ok(Array.isArray(nodes));
assert.equal(nodes.length, 2);
assert.ok(nodes[0] instanceof Node);
assert.ok(nodes[1] instanceof Node);
assert.equal(nodes[0].compile().eval(), 5);
assert.equal(nodes[1].compile().eval(), 9);
});
it('should LaTeX parse', function () {
var expression = math.parse('parse(expr,options)');
assert.equal(expression.toTex(), '\\mathrm{parse}\\left( expr, options\\right)');
});
});

View File

@@ -0,0 +1,19 @@
var assert = require('assert');
var math = require('../../../index');
var Parser = math.expression.Parser;
describe('parser', function() {
it('should create a parser', function() {
var parser = math.parser();
assert(parser instanceof Parser);
});
it('should LaTeX parser', function () { //This doesn't really make sense in a way
var expression = math.parse('parser()');
assert.equal(expression.toTex(), '\\mathrm{parser}\\left(\\right)');
});
});

View File

@@ -0,0 +1,11 @@
// test keywords
var assert = require('assert'),
keywords = require('../../lib/expression/keywords');
describe('keywords', function() {
it('should return a map with reserved keywords', function() {
assert.deepEqual(Object.keys(keywords).sort(), ['end'].sort());
});
});

View File

@@ -0,0 +1,465 @@
// test AccessorNode
var assert = require('assert');
var approx = require('../../../tools/approx');
var math = require('../../../index');
var bigmath = require('../../../index').create({number: 'BigNumber'});
var Node = math.expression.node.Node;
var ConstantNode = math.expression.node.ConstantNode;
var OperatorNode = math.expression.node.OperatorNode;
var SymbolNode = math.expression.node.SymbolNode;
var AccessorNode = math.expression.node.AccessorNode;
var IndexNode = math.expression.node.IndexNode;
var RangeNode = math.expression.node.RangeNode;
describe('AccessorNode', function() {
it ('should create a AccessorNode', function () {
var n = new AccessorNode(new Node(), new IndexNode([]));
assert(n instanceof AccessorNode);
assert(n instanceof Node);
assert.equal(n.type, 'AccessorNode');
});
it ('should have isAccessorNode', function () {
var node = new AccessorNode(new Node(), new IndexNode([]));
assert(node.isAccessorNode);
});
it ('should throw an error when calling with wrong arguments', function () {
assert.throws(function () {new AccessorNode()}, TypeError);
assert.throws(function () {new AccessorNode('a', new IndexNode([]))}, TypeError);
assert.throws(function () {new AccessorNode(new Node, new IndexNode([2, 3]))}, TypeError);
assert.throws(function () {new AccessorNode(new Node, new IndexNode([new Node(), 3]))}, TypeError);
});
it ('should throw an error when calling without new operator', function () {
assert.throws(function () {AccessorNode(new Node(), new IndexNode([]))}, SyntaxError);
});
it ('should get the name of an AccessorNode', function () {
var n = new AccessorNode(new SymbolNode('a'), new IndexNode([new ConstantNode('toString')]));
assert.equal(n.name, 'toString');
var n = new AccessorNode(new SymbolNode('a'), new IndexNode([new ConstantNode(1)]));
assert.equal(n.name, '');
});
it ('should compile a AccessorNode', function () {
var a = new bigmath.expression.node.SymbolNode('a');
var index = new IndexNode([
new bigmath.expression.node.ConstantNode(2),
new bigmath.expression.node.ConstantNode(1)
]);
var n = new bigmath.expression.node.AccessorNode(a, index);
var expr = n.compile();
var scope = {
a: [[1, 2], [3, 4]]
};
assert.equal(expr.eval(scope), 3);
});
it ('should compile a AccessorNode with range and context parameters', function () {
var a = new SymbolNode('a');
var index = new IndexNode([
new ConstantNode(2),
new RangeNode(
new ConstantNode(1),
new SymbolNode('end')
)
]);
var n = new AccessorNode(a, index);
var expr = n.compile();
var scope = {
a: [[1, 2], [3, 4]]
};
assert.deepEqual(expr.eval(scope), [[3, 4]]);
});
it ('should compile a AccessorNode with a property', function () {
var a = new SymbolNode('a');
var index = new IndexNode([new ConstantNode('b')]);
var n = new AccessorNode(a, index);
var expr = n.compile();
var scope = {
a: { b: 42 }
};
assert.deepEqual(expr.eval(scope), 42);
});
it ('should throw a one-based index error when out of range (Array)', function () {
var a = new SymbolNode('a');
var index = new IndexNode([new ConstantNode(4)]);
var n = new AccessorNode(a, index);
var expr = n.compile();
var scope = {
a: [1,2,3]
};
assert.throws(function () { expr.eval(scope) }, /Index out of range \(4 > 3\)/);
});
it ('should throw a one-based index error when out of range (Matrix)', function () {
var a = new SymbolNode('a');
var index = new IndexNode([new ConstantNode(4)]);
var n = new AccessorNode(a, index);
var expr = n.compile();
var scope = {
a: math.matrix([1,2,3])
};
assert.throws(function () { expr.eval(scope) }, /Index out of range \(4 > 3\)/);
});
it ('should throw a one-based index error when out of range (string)', function () {
var a = new SymbolNode('a');
var index = new IndexNode([new ConstantNode(4)]);
var n = new AccessorNode(a, index);
var expr = n.compile();
var scope = {
a: 'hey'
};
assert.throws(function () { expr.eval(scope) }, /Index out of range \(4 > 3\)/);
});
it ('should throw an error when applying a matrix index onto an object', function () {
var a = new SymbolNode('a');
var index = new IndexNode([new ConstantNode(4)]);
var n = new AccessorNode(a, index);
var expr = n.compile();
var scope = {
a: {}
};
assert.throws(function () { expr.eval(scope) }, /Cannot apply a numeric index as object property/);
});
it ('should throw an error when applying an index onto a scalar', function () {
var a = new SymbolNode('a');
var index = new IndexNode([new ConstantNode(4)]);
var n = new AccessorNode(a, index);
var expr = n.compile();
var scope = {
a: 42
};
assert.throws(function () { expr.eval(scope) }, /Cannot apply index: unsupported type of object/);
});
it ('should compile a AccessorNode with negative step range and context parameters', function () {
var a = new SymbolNode('a');
var index = new IndexNode([
new ConstantNode(2),
new RangeNode(
new SymbolNode('end'),
new ConstantNode(1),
new ConstantNode(-1)
)
]);
var n = new AccessorNode(a, index);
var expr = n.compile();
var scope = {
a: [[1, 2], [3, 4]]
};
assert.deepEqual(expr.eval(scope), [[4, 3]]);
});
it ('should compile a AccessorNode with "end" both as value and in a range', function () {
var a = new SymbolNode('a');
var index = new IndexNode([
new SymbolNode('end'),
new RangeNode(
new ConstantNode(1),
new SymbolNode('end')
)
]);
var n = new AccessorNode(a, index);
var expr = n.compile();
var scope = {
a: [[1, 2], [3, 4]]
};
assert.deepEqual(expr.eval(scope), [[3, 4]]);
});
it ('should compile a AccessorNode with bignumber setting', function () {
var a = new bigmath.expression.node.SymbolNode('a');
var b = new bigmath.expression.node.ConstantNode(2);
var c = new bigmath.expression.node.ConstantNode(1);
var n = new bigmath.expression.node.AccessorNode(a, new IndexNode([b, c]));
var expr = n.compile();
var scope = {
a: [[1, 2], [3, 4]]
};
assert.deepEqual(expr.eval(scope), 3);
});
it ('should filter an AccessorNode', function () {
var a = new SymbolNode('a');
var b = new ConstantNode(2);
var c = new ConstantNode(1);
var index = new IndexNode([b, c]);
var n = new AccessorNode(a, index);
assert.deepEqual(n.filter(function (node) {return node.isAccessorNode}), [n]);
assert.deepEqual(n.filter(function (node) {return node.isSymbolNode}), [a]);
assert.deepEqual(n.filter(function (node) {return node.isRangeNode}), []);
assert.deepEqual(n.filter(function (node) {return node.isConstantNode}), [b, c]);
assert.deepEqual(n.filter(function (node) {return node.isConstantNode && node.value == '2'}), [b]);
assert.deepEqual(n.filter(function (node) {return node.isConstantNode && node.value == '4'}), []);
});
it ('should filter an empty AccessorNode', function () {
var n = new AccessorNode(new SymbolNode('a'), new IndexNode([]));
assert.deepEqual(n.filter(function (node) {return node.isAccessorNode}), [n]);
assert.deepEqual(n.filter(function (node) {return node.isConstantNode}), []);
});
it ('should run forEach on an AccessorNode', function () {
var a = new SymbolNode('a');
var b = new ConstantNode(2);
var c = new ConstantNode(1);
var index = new IndexNode([b, c]);
var n = new AccessorNode(a, index);
var nodes = [];
var paths = [];
n.forEach(function (node, path, parent) {
nodes.push(node);
paths.push(path);
assert.strictEqual(parent, n);
});
assert.equal(nodes.length, 2);
assert.strictEqual(nodes[0], a);
assert.strictEqual(nodes[1], index);
assert.deepEqual(paths, ['object', 'index']);
});
it ('should map an AccessorNode', function () {
var a = new SymbolNode('a');
var b = new ConstantNode(2);
var c = new ConstantNode(1);
var index = new IndexNode([b, c]);
var n = new AccessorNode(a, index);
var nodes = [];
var paths = [];
var e = new SymbolNode('c');
var f = n.map(function (node, path, parent) {
nodes.push(node);
paths.push(path);
assert.strictEqual(parent, n);
return node instanceof SymbolNode ? e : node;
});
assert.equal(nodes.length, 2);
assert.strictEqual(nodes[0], a);
assert.strictEqual(nodes[1], index);
assert.deepEqual(paths, ['object', 'index']);
assert.notStrictEqual(f, n);
assert.deepEqual(f.object, e);
assert.deepEqual(f.index.dimensions[0], b);
assert.deepEqual(f.index.dimensions[1], c);
});
it ('should throw an error when the map callback does not return a node', function () {
var a = new SymbolNode('a');
var b = new ConstantNode(2);
var c = new ConstantNode(1);
var n = new AccessorNode(a, new IndexNode([b, c]));
assert.throws(function () {
n.map(function () {});
}, /Callback function must return a Node/)
});
it ('should transform an IndexNodes object', function () {
var a = new SymbolNode('a');
var b = new ConstantNode(2);
var c = new ConstantNode(1);
var n = new AccessorNode(a, new IndexNode([b, c]));
var e = new SymbolNode('c');
var f = n.transform(function (node) {
return node instanceof SymbolNode ? e : node;
});
assert.notStrictEqual(f, n);
assert.deepEqual(f.object, e);
assert.deepEqual(f.index.dimensions[0], b);
assert.deepEqual(f.index.dimensions[1], c);
});
it ('should transform an IndexNodes (nested) parameters', function () {
var a = new SymbolNode('a');
var b = new ConstantNode(2);
var c = new ConstantNode(1);
var n = new AccessorNode(a, new IndexNode([b, c]));
var e = new SymbolNode('c');
var f = n.transform(function (node) {
return node instanceof ConstantNode && node.value == '1' ? e : node;
});
assert.notStrictEqual(f, n);
assert.deepEqual(f.object, a);
assert.deepEqual(f.index.dimensions[0], b);
assert.deepEqual(f.index.dimensions[1], e);
});
it ('should transform an AccessorNode itself', function () {
var a = new SymbolNode('a');
var b = new ConstantNode(2);
var c = new ConstantNode(1);
var n = new AccessorNode(a, new IndexNode([b, c]));
var e = new ConstantNode(5);
var f = n.transform(function (node) {
return node instanceof AccessorNode ? e : node;
});
assert.notStrictEqual(f, n);
assert.deepEqual(f, e);
});
it ('should clone an AccessorNode', function () {
var a = new SymbolNode('a');
var b = new ConstantNode(2);
var c = new ConstantNode(1);
var n = new AccessorNode(a, new IndexNode([b, c]));
var d = n.clone();
assert(d instanceof AccessorNode);
assert.deepEqual(d, n);
assert.notStrictEqual(d, n);
assert.strictEqual(d.object, n.object);
assert.strictEqual(d.index, n.index);
assert.strictEqual(d.index.dimensions[0], n.index.dimensions[0]);
assert.strictEqual(d.index.dimensions[1], n.index.dimensions[1]);
});
it ('should test equality of an Node', function () {
var a = new SymbolNode('a');
var b = new ConstantNode(2);
var c = new ConstantNode(1);
var node1 = new AccessorNode(a, new IndexNode([b, c]));
var a = new SymbolNode('a');
var b = new SymbolNode('b');
var c = new ConstantNode(1);
var node2 = new AccessorNode(a, new IndexNode([b, c]));
var a = new SymbolNode('a');
var b = new ConstantNode(2);
var c = new ConstantNode(1);
var node3 = new AccessorNode(a, new IndexNode([b, c]));
assert.strictEqual(node1.equals(null), false);
assert.strictEqual(node1.equals(undefined), false);
assert.strictEqual(node1.equals(node2), false);
assert.strictEqual(node1.equals(node3), true);
});
it ('should stringify an AccessorNode', function () {
var a = new SymbolNode('a');
var index = new IndexNode([
new ConstantNode(2),
new ConstantNode(1)
]);
var n = new AccessorNode(a, index);
assert.equal(n.toString(), 'a[2, 1]');
var n2 = new AccessorNode(a, new IndexNode([]));
assert.equal(n2.toString(), 'a[]')
});
it ('should stringify an AccessorNode with parentheses', function () {
var a = new SymbolNode('a');
var b = new SymbolNode('b');
var add = new OperatorNode('+', 'add', [a, b]);
var bar = new AccessorNode(add, new IndexNode([new ConstantNode('bar')]));
assert.equal(bar.toString(), '(a + b)["bar"]');
});
it ('should stringify nested AccessorNode', function () {
var a = new SymbolNode('a');
var foo = new AccessorNode(a, new IndexNode([new ConstantNode('foo')]));
var bar = new AccessorNode(foo, new IndexNode([new ConstantNode('bar')]));
assert.equal(bar.toString(), 'a["foo"]["bar"]');
});
it ('should stringigy an AccessorNode with custom toString', function () {
//Also checks if the custom functions get passed on to the children
var customFunction = function (node, options) {
if (node.type === 'AccessorNode') {
var string = node.object.toString(options) + ' at ';
node.index.dimensions.forEach(function (range) {
string += range.toString(options) + ', ';
});
return string;
}
else if (node.type === 'ConstantNode') {
return 'const(' + node.value + ', ' + node.valueType + ')'
}
};
var a = new SymbolNode('a');
var b = new ConstantNode(1);
var c = new ConstantNode(2);
var n = new AccessorNode(a, new IndexNode([b, c]));
assert.equal(n.toString({handler: customFunction}), 'a at const(1, number), const(2, number), ');
});
it ('should LaTeX an AccessorNode', function () {
var a = new SymbolNode('a');
var index = new IndexNode([
new ConstantNode(2),
new ConstantNode(1)
]);
var n = new AccessorNode(a, index);
assert.equal(n.toTex(), ' a_{2,1}');
var n2 = new AccessorNode(a, new IndexNode([]));
assert.equal(n2.toTex(), ' a_{}')
});
it ('should LaTeX an AccessorNode with custom toTex', function () {
//Also checks if the custom functions get passed on to the children
var customFunction = function (node, options) {
if (node.type === 'AccessorNode') {
var latex = node.object.toTex(options) + ' at ';
node.index.dimensions.forEach(function (range) {
latex += range.toTex(options) + ', ';
});
return latex;
}
else if (node.type === 'ConstantNode') {
return 'const\\left(' + node.value + ', ' + node.valueType + '\\right)'
}
};
var a = new SymbolNode('a');
var b = new ConstantNode(1);
var c = new ConstantNode(2);
var n = new AccessorNode(a, new IndexNode([b, c]));
assert.equal(n.toTex({handler: customFunction}), ' a at const\\left(1, number\\right), const\\left(2, number\\right), ');
});
});

View File

@@ -0,0 +1,318 @@
// test ArrayNode
var assert = require('assert');
var approx = require('../../../tools/approx');
var math = require('../../../index');
var Node = math.expression.node.Node;
var ConstantNode = math.expression.node.ConstantNode;
var SymbolNode = math.expression.node.SymbolNode;
var RangeNode = math.expression.node.RangeNode;
var ArrayNode = math.expression.node.ArrayNode;
describe('ArrayNode', function() {
it ('should create an ArrayNode', function () {
var c = new ConstantNode(1);
var a = new ArrayNode([c]);
var b = new ArrayNode([]);
assert(a instanceof ArrayNode);
assert(b instanceof ArrayNode);
assert.equal(a.type, 'ArrayNode');
assert.equal(b.type, 'ArrayNode');
});
it ('should have isArrayNode', function () {
var node = new ArrayNode([]);
assert(node.isArrayNode);
});
it ('should throw an error when calling without new operator', function () {
assert.throws(function () {ArrayNode()}, SyntaxError);
});
it ('should throw an error on wrong constructor arguments', function () {
assert.throws(function () {new ArrayNode(2)}, TypeError);
assert.throws(function () {new ArrayNode([2, 3])}, TypeError);
});
it ('should evaluate an ArrayNode', function () {
var c = new ConstantNode(1);
var a = new ArrayNode([c]);
var b = new ArrayNode();
assert.deepEqual(a.compile().eval(), math.matrix([1]));
assert.deepEqual(b.compile().eval(), math.matrix([]));
});
it ('should compile an ArrayNode and evaluate as Matrix', function () {
var a = new ConstantNode(1);
var b = new ConstantNode(2);
var c = new ConstantNode(3);
var d = new ConstantNode(4);
var n = new ArrayNode([a, b, c, d]);
var expr = n.compile();
assert.deepEqual(expr.eval(), math.matrix([1,2,3,4]));
});
it ('should compile an ArrayNode and evaluate as Array', function () {
var mathArray = math.create({matrix: 'Array'});
var a = new mathArray.expression.node.ConstantNode(1);
var b = new mathArray.expression.node.ConstantNode(2);
var c = new mathArray.expression.node.ConstantNode(3);
var d = new mathArray.expression.node.ConstantNode(4);
var n = new mathArray.expression.node.ArrayNode([a, b, c, d]);
var expr = n.compile();
assert.deepEqual(expr.eval(), [1,2,3,4]);
});
it ('should compile nested ArrayNodes', function () {
var a = new ConstantNode(1);
var b = new ConstantNode(2);
var c = new ConstantNode(3);
var d = new ConstantNode(4);
var n2 = new ArrayNode([a, b]);
var n3 = new ArrayNode([c, d]);
var n4 = new ArrayNode([n2, n3]);
var expr = n4.compile();
assert.deepEqual(expr.eval(), math.matrix([[1,2],[3,4]]));
});
it ('should find an ArrayNode', function () {
var a = new ConstantNode(1);
var b = new SymbolNode('x');
var c = new ConstantNode(2);
var d = new ArrayNode([a, b, c]);
assert.deepEqual(d.filter(function (node) {return node instanceof ArrayNode}), [d]);
assert.deepEqual(d.filter(function (node) {return node instanceof SymbolNode}), [b]);
assert.deepEqual(d.filter(function (node) {return node instanceof RangeNode}), []);
assert.deepEqual(d.filter(function (node) {return node instanceof ConstantNode}), [a, c]);
assert.deepEqual(d.filter(function (node) {return node instanceof ConstantNode && node.value == '2'}), [c]);
});
it ('should run forEach on an ArrayNode', function () {
// [x, 2]
var a = new SymbolNode('x');
var b = new ConstantNode(2);
var c = new ArrayNode([a, b]);
var d = new ConstantNode(3);
var nodes = [];
var paths = [];
c.forEach(function (node, path, parent) {
nodes.push(node);
paths.push(path);
assert.strictEqual(parent, c);
});
assert.deepEqual(paths, ['items[0]', 'items[1]']);
assert.equal(nodes.length, 2);
assert.strictEqual(nodes[0], a);
assert.strictEqual(nodes[1], b);
});
it ('should map an ArrayNode', function () {
// [x, 2]
var a = new SymbolNode('x');
var b = new ConstantNode(2);
var c = new ArrayNode([a, b]);
var d = new ConstantNode(3);
var nodes = [];
var paths = [];
var e = c.map(function (node, path, parent) {
nodes.push(node);
paths.push(path);
assert.strictEqual(parent, c);
return (node instanceof SymbolNode) && (node.name == 'x') ? d : node;
});
assert.deepEqual(paths, ['items[0]', 'items[1]']);
assert.equal(nodes.length, 2);
assert.strictEqual(nodes[0], a);
assert.strictEqual(nodes[1], b);
assert.notStrictEqual(e, c);
assert.deepEqual(e.items[0], d);
assert.deepEqual(e.items[1], b);
});
it ('should throw an error when the map callback does not return a node', function () {
var a = new SymbolNode('x');
var b = new ConstantNode(2);
var c = new ArrayNode([a, b]);
assert.throws(function () {
c.map(function () {});
}, /Callback function must return a Node/)
});
it ('should transform an ArrayNodes parameters', function () {
// [x, 2]
var a = new SymbolNode('x');
var b = new ConstantNode(2);
var c = new ArrayNode([a, b]);
var d = new ConstantNode(3);
var e = c.transform(function (node) {
return (node instanceof SymbolNode) && (node.name == 'x') ? d : node;
});
assert.notStrictEqual(e, c);
assert.deepEqual(e.items[0], d);
assert.deepEqual(e.items[1], b);
});
it ('should transform an ArrayNode itself', function () {
// [x, 2]
var a = new SymbolNode('x');
var b = new ConstantNode(2);
var c = new ArrayNode([a, b]);
var d = new ConstantNode(3);
var e = c.transform(function (node) {
return (node instanceof ArrayNode) ? d : node;
});
assert.notStrictEqual(e, c);
assert.deepEqual(e, d);
});
it ('should traverse an ArrayNode', function () {
var a = new ConstantNode(1);
var b = new ConstantNode(2);
var c = new ArrayNode([a, b]);
var count = 0;
c.traverse(function (node, path, parent) {
count++;
switch(count) {
case 1:
assert.strictEqual(node, c);
assert.strictEqual(path, null);
assert.strictEqual(parent, null);
break;
case 2:
assert.strictEqual(node, a);
assert.strictEqual(path, 'items[0]');
assert.strictEqual(parent, c);
break;
case 3:
assert.strictEqual(node, b);
assert.strictEqual(path, 'items[1]');
assert.strictEqual(parent, c);
break;
}
});
assert.equal(count, 3);
});
it ('should clone an ArrayNode', function () {
// [x, 2]
var a = new SymbolNode('x');
var b = new ConstantNode(2);
var c = new ArrayNode([a, b]);
var d = c.clone();
assert(d instanceof ArrayNode);
assert.deepEqual(c, d);
assert.notStrictEqual(c, d);
assert.strictEqual(c.items[0], d.items[0]);
assert.strictEqual(c.items[1], d.items[1]);
});
it ('test equality with other nodes', function () {
// [x, 2]
var a = new SymbolNode('x');
var b = new ConstantNode(2);
var c = new ArrayNode([a, b]);
assert.strictEqual(c.equals(null), false);
assert.strictEqual(c.equals(undefined), false);
assert.strictEqual(c.equals(new ArrayNode([new SymbolNode('x'), new ConstantNode(2)])), true);
assert.strictEqual(c.equals(new ArrayNode([new SymbolNode('x'), new ConstantNode(2), new ConstantNode(3)])), false);
assert.strictEqual(c.equals(new ArrayNode([new SymbolNode('x'), new ConstantNode(3)])), false);
assert.strictEqual(c.equals(new ArrayNode([new SymbolNode('x')])), false);
});
it ('should stringify an ArrayNode', function () {
var a = new ConstantNode(1);
var b = new ConstantNode(2);
var c = new ConstantNode(3);
var d = new ConstantNode(4);
var n = new ArrayNode([a, b, c, d]);
assert.equal(n.toString(), '[1, 2, 3, 4]');
});
it ('should stringify an ArrayNode with custom toString', function () {
//Also checks if the custom functions get passed on to the children
var customFunction = function (node, options) {
if (node.type === 'ArrayNode') {
var string = '[';
node.items.forEach(function (item) {
string += item.toString(options) + ', ';
});
string += ']';
return string;
}
else if (node.type === 'ConstantNode') {
return 'const(' + node.value + ', ' + node.valueType + ')'
}
};
var a = new ConstantNode(1);
var b = new ConstantNode(2);
var n = new ArrayNode([a, b]);
assert.equal(n.toString({handler: customFunction}), '[const(1, number), const(2, number), ]');
});
it ('should LaTeX an ArrayNode', function () {
var a = new ConstantNode(1);
var b = new ConstantNode(2);
var c = new ConstantNode(3);
var d = new ConstantNode(4);
var v1 = new ArrayNode([a, b]);
var v2 = new ArrayNode([c, d]);
var n = new ArrayNode([v1, v2]);
assert.equal(n.toTex(), '\\begin{bmatrix}1&2\\\\3&4\\\\\\end{bmatrix}');
});
it ('should LaTeX an ArrayNode with custom toTex', function () {
//Also checks if the custom functions get passed on to the children
var customFunction = function (node, options) {
if (node.type === 'ArrayNode') {
var latex = '\\left[';
node.items.forEach(function (item) {
latex += item.toTex(options) + ', ';
});
latex += '\\right]';
return latex;
}
else if (node.type === 'ConstantNode') {
return 'const\\left(' + node.value + ', ' + node.valueType + '\\right)'
}
};
var a = new ConstantNode(1);
var b = new ConstantNode(2);
var n = new ArrayNode([a, b]);
assert.equal(n.toTex({handler: customFunction}), '\\left[const\\left(1, number\\right), const\\left(2, number\\right), \\right]');
});
});

View File

@@ -0,0 +1,547 @@
// test AssignmentNode
var assert = require('assert');
var approx = require('../../../tools/approx');
var math = require('../../../index');
var Node = math.expression.node.Node;
var AccessorNode = math.expression.node.AccessorNode;
var ConstantNode = math.expression.node.ConstantNode;
var SymbolNode = math.expression.node.SymbolNode;
var RangeNode = math.expression.node.RangeNode;
var ArrayNode = math.expression.node.ArrayNode;
var AssignmentNode = math.expression.node.AssignmentNode;
var OperatorNode = math.expression.node.OperatorNode;
var IndexNode = math.expression.node.IndexNode;
describe('AssignmentNode', function() {
it ('should create an AssignmentNode', function () {
var n = new AssignmentNode(new SymbolNode('a'), new Node());
assert(n instanceof AssignmentNode);
assert(n instanceof Node);
assert.equal(n.type, 'AssignmentNode');
});
it ('should have isAssignmentNode', function () {
var node = new AssignmentNode(new SymbolNode('a'), new Node());
assert(node.isAssignmentNode);
});
it ('should throw an error when calling without new operator', function () {
assert.throws(function () {AssignmentNode(new SymbolNode('a'), new Node())}, SyntaxError);
});
it ('should throw an error when creating an AssignmentNode with a reserved keyword', function () {
assert.throws(function () {
new AssignmentNode(new SymbolNode('end'), new Node());
}, /Cannot assign to symbol "end"/)
});
it ('should throw an error on wrong constructor arguments', function () {
assert.throws(function () {new AssignmentNode()}, TypeError );
assert.throws(function () {new AssignmentNode(new Node(), new Node())}, TypeError );
assert.throws(function () {new AssignmentNode('a', new Node())}, TypeError );
assert.throws(function () {new AssignmentNode(2, new Node())}, TypeError );
assert.throws(function () {new AssignmentNode(new Node(), new Node(), new Node())}, TypeError );
});
it ('should get the name of an AssignmentNode', function () {
var n = new AssignmentNode(new SymbolNode('a'), new ConstantNode(1));
assert.equal(n.name, 'a');
var n2 = new AccessorNode(new SymbolNode('a'), new IndexNode([new ConstantNode('b')]));
var n3 = new AssignmentNode(n2, new ConstantNode(1));
assert.equal(n3.name, 'b');
var n4 = new AssignmentNode(new SymbolNode('a'), new IndexNode([new ConstantNode('b')]), new ConstantNode(1));
assert.equal(n4.name, 'b');
var n5 = new AssignmentNode(new SymbolNode('a'), new IndexNode([new ConstantNode(1)]), new ConstantNode(1));
assert.equal(n5.name, '');
});
it ('should compile an AssignmentNode without index', function () {
var n = new AssignmentNode(new SymbolNode('b'), new ConstantNode(3));
var expr = n.compile();
var scope = {};
assert.equal(expr.eval(scope), 3);
assert.equal(scope.b, 3);
});
it ('should compile an AssignmentNode with property index', function () {
var object = new SymbolNode('a');
var index = new IndexNode([new ConstantNode('b')]);
var value = new ConstantNode(3);
var n = new AssignmentNode(object, index, value);
var expr = n.compile();
var scope = {
a: {}
};
assert.equal(expr.eval(scope), 3);
assert.deepEqual(scope, {a: {b: 3}});
});
it ('should compile an AssignmentNode with nested property index', function () {
var a = new SymbolNode('a');
var object = new AccessorNode(a, new IndexNode([new ConstantNode('b')]));
var index = new IndexNode([new ConstantNode('c')]);
var value = new ConstantNode(3);
var n = new AssignmentNode(object, index, value);
var expr = n.compile();
var scope = {
a: {
b: {}
}
};
assert.equal(expr.eval(scope), 3);
assert.deepEqual(scope, {a: {b: {c: 3}}});
});
it ('should compile an AssignmentNode with matrix index', function () {
var object = new SymbolNode('a');
var index = new IndexNode([
new ConstantNode(2),
new ConstantNode(1)
]);
var value = new ConstantNode(5);
var n = new AssignmentNode(object, index, value);
var expr = n.compile();
var scope = {
a: [[0, 0], [0, 0]]
};
assert.strictEqual(expr.eval(scope), 5);
assert.deepEqual(scope, {
a: [[0, 0], [5, 0]]
});
});
it ('should compile an AssignmentNode with range and context parameters', function () {
var object = new SymbolNode('a');
var index = new IndexNode([
new ConstantNode(2),
new RangeNode(
new ConstantNode(1),
new SymbolNode('end')
)
]);
var value = new SymbolNode('b');
var n = new AssignmentNode(object, index, value);
var expr = n.compile();
var scope = {
a: [[0, 0], [0, 0]],
b: [5, 6]
};
assert.deepEqual(expr.eval(scope), [5, 6]);
assert.deepEqual(scope, {
a: [[0, 0], [5, 6]],
b: [5, 6]
});
});
it ('should compile an AssignmentNode with bignumber setting', function () {
var bigmath = math.create({number: 'BigNumber'});
var object = new SymbolNode('a');
var index = new bigmath.expression.node.IndexNode([
new bigmath.expression.node.ConstantNode(2),
new bigmath.expression.node.ConstantNode(1)
]);
var value = new bigmath.expression.node.ConstantNode(5);
var n = new bigmath.expression.node.AssignmentNode(object, index, value);
var expr = n.compile();
var scope = {
a: [[0, 0], [0, 0]]
};
assert.deepEqual(expr.eval(scope), bigmath.bignumber(5));
assert.deepEqual(scope, {
a: [[0, 0], [bigmath.bignumber(5), 0]]
});
});
it ('should throw an error when applying an index onto a scalar', function () {
var a = new SymbolNode('a');
var index = new IndexNode([new ConstantNode(4)]);
var value = new ConstantNode(2);
var n = new AssignmentNode(a, index, value);
var expr = n.compile();
var scope = {
a: 42
};
assert.throws(function () { expr.eval(scope) }, /Cannot apply index: unsupported type of object/);
});
it ('should filter an AssignmentNode', function () {
var a = new SymbolNode('a');
var b = new ConstantNode(2);
var c = new ConstantNode(1);
var i = new IndexNode([b, c]);
var v = new ConstantNode(2);
var n = new AssignmentNode(a, i, v);
assert.deepEqual(n.filter(function (node) {return node.isAssignmentNode}), [n]);
assert.deepEqual(n.filter(function (node) {return node.isSymbolNode}), [a]);
assert.deepEqual(n.filter(function (node) {return node.isConstantNode}), [b, c, v]);
assert.deepEqual(n.filter(function (node) {return node.value === '1'}), [c]);
assert.deepEqual(n.filter(function (node) {return node.value === '2'}), [b, v]);
assert.deepEqual(n.filter(function (node) {return node.name === 'q'}), []);
});
it ('should filter an AssignmentNode without index', function () {
var a = new SymbolNode('a');
var v = new ConstantNode(2);
var n = new AssignmentNode(a, v);
assert.deepEqual(n.filter(function (node) {return node.isAssignmentNode}), [n]);
assert.deepEqual(n.filter(function (node) {return node.isSymbolNode}), [a]);
assert.deepEqual(n.filter(function (node) {return node.isConstantNode}), [v]);
assert.deepEqual(n.filter(function (node) {return node.value === '2'}), [v]);
assert.deepEqual(n.filter(function (node) {return node.name === 'q'}), []);
});
it ('should run forEach on an AssignmentNode', function () {
// A[1, x] = 3
var a = new SymbolNode('A');
var b = new ConstantNode(2);
var c = new SymbolNode('x');
var i = new IndexNode([b, c]);
var v = new ConstantNode(3);
var n = new AssignmentNode(a, i, v);
var nodes = [];
var paths = [];
n.forEach(function (node, path, parent) {
nodes.push(node);
paths.push(path);
assert.strictEqual(parent, n);
});
assert.equal(nodes.length, 3);
assert.strictEqual(nodes[0], a);
assert.strictEqual(nodes[1], i);
assert.strictEqual(nodes[2], v);
assert.deepEqual(paths, ['object', 'index', 'value']);
});
it ('should run forEach on an AssignmentNode without index', function () {
// A[1, x] = 3
var a = new SymbolNode('A');
var v = new ConstantNode(3);
var n = new AssignmentNode(a, v);
var nodes = [];
var paths = [];
n.forEach(function (node, path, parent) {
nodes.push(node);
paths.push(path);
assert.strictEqual(parent, n);
});
assert.equal(nodes.length, 2);
assert.strictEqual(nodes[0], a);
assert.strictEqual(nodes[1], v);
assert.deepEqual(paths, ['object', 'value']);
});
it ('should map an AssignmentNode', function () {
// A[1, x] = 3
var a = new SymbolNode('A');
var b = new ConstantNode(2);
var c = new SymbolNode('x');
var i = new IndexNode([b, c]);
var v = new ConstantNode(3);
var n = new AssignmentNode(a, i, v);
var nodes = [];
var paths = [];
var e = new ConstantNode(4);
var f = n.map(function (node, path, parent) {
nodes.push(node);
paths.push(path);
assert.strictEqual(parent, n);
return node instanceof SymbolNode && node.name == 'x' ? e : node;
});
assert.equal(nodes.length, 3);
assert.strictEqual(nodes[0], a);
assert.strictEqual(nodes[1], i);
assert.strictEqual(nodes[2], v);
assert.deepEqual(paths, ['object', 'index', 'value']);
assert.notStrictEqual(f, n);
assert.deepEqual(f.object, a);
assert.deepEqual(f.index.dimensions[0], b);
assert.deepEqual(f.index.dimensions[1], c); // not replaced, is nested
assert.deepEqual(f.value, v);
});
it ('should map an AssignmentNode without index', function () {
// a = x + 2
var a = new SymbolNode('a');
var x = new SymbolNode('x');
var d = new AssignmentNode(a, x);
var e = new ConstantNode(3);
var nodes = [];
var paths = [];
var f = d.map(function (node, path, parent) {
nodes.push(node);
paths.push(path);
assert.strictEqual(parent, d);
return node instanceof SymbolNode && node.name == 'x' ? e : node;
});
assert.equal(nodes.length, 2);
assert.strictEqual(nodes[0], a);
assert.strictEqual(nodes[1], x);
assert.deepEqual(paths, ['object', 'value']);
assert.notStrictEqual(f, d);
assert.strictEqual(d.value, x);
assert.strictEqual(f.value, e);
});
it ('should throw an error when the map callback does not return a node', function () {
// A[1, x] = 3
var a = new SymbolNode('A');
var b = new ConstantNode(2);
var c = new SymbolNode('x');
var i = new IndexNode([b, c]);
var v = new ConstantNode(3);
var n = new AssignmentNode(a, i, v);
assert.throws(function () {
n.map(function () {});
}, /Callback function must return a Node/)
});
it ('should transform an AssignmentNodes (nested) parameters', function () {
// a = x + 2
var object = new SymbolNode('a');
var x = new SymbolNode('x');
var index = new IndexNode([x]);
var b = new ConstantNode(2);
var value = new OperatorNode('+', 'add', [x, b]);
var d = new AssignmentNode(object, index, value);
var e = new ConstantNode(3);
var f = d.transform(function (node) {
return node.isSymbolNode && node.name == 'x' ? e : node;
});
assert.notStrictEqual(f, d);
assert.deepEqual(f.index.dimensions[0], e);
assert.deepEqual(f.value.args[0], e);
assert.deepEqual(f.value.args[1], b);
});
it ('should transform an AssignmentNode itself', function () {
// a = x + 2
var object = new SymbolNode('a');
var x = new SymbolNode('x');
var b = new ConstantNode(2);
var c = new OperatorNode('+', 'add', [x, b]);
var d = new AssignmentNode(object, c);
var e = new ConstantNode(5);
var f = d.transform(function (node) {
return node instanceof AssignmentNode ? e : node;
});
assert.notStrictEqual(f, d);
assert.deepEqual(f, e);
});
it ('should traverse an AssignmentNode', function () {
var object = new SymbolNode('a');
var i = new IndexNode([]);
var value = new ConstantNode(2);
var a = new AssignmentNode(object, i, value);
var count = 0;
a.traverse(function (node, index, parent) {
count++;
switch(count) {
case 1:
assert.strictEqual(node, a);
assert.strictEqual(index, null);
assert.strictEqual(parent, null);
break;
case 2:
assert.strictEqual(node, object);
assert.strictEqual(index, 'object');
assert.strictEqual(parent, a);
break;
case 3:
assert.strictEqual(node, i);
assert.strictEqual(index, 'index');
assert.strictEqual(parent, a);
break;
case 4:
assert.strictEqual(node, value);
assert.strictEqual(index, 'value');
assert.strictEqual(parent, a);
break;
}
});
assert.equal(count, 4);
});
it ('should clone an AssignmentNode without index', function () {
var object = new SymbolNode('a');
var value = new ConstantNode(2);
var a = new AssignmentNode(object, value);
var b = a.clone();
assert(b instanceof AssignmentNode);
assert.deepEqual(b, a);
assert.notStrictEqual(b, a);
assert.strictEqual(b.object, a.object);
assert.strictEqual(b.index, a.index);
assert.strictEqual(b.value, a.value);
});
it ('should clone an AssignmentNode', function () {
// A[1, x] = 3
var a = new SymbolNode('A');
var b = new ConstantNode(2);
var c = new SymbolNode('x');
var i = new IndexNode([b, c]);
var v = new ConstantNode(3);
var d = new AssignmentNode(a, i, v);
var e = d.clone();
assert(e instanceof AssignmentNode);
assert.deepEqual(e, d);
assert.notStrictEqual(e, d);
assert.strictEqual(e.object, d.object);
assert.strictEqual(e.index, d.index);
assert.strictEqual(e.value, d.value);
});
it ('test equality another Node', function () {
var a = new AssignmentNode(
new SymbolNode('A'),
new IndexNode([new ConstantNode(2), new SymbolNode('x')]),
new ConstantNode(3));
var b = new AssignmentNode(
new SymbolNode('A'),
new IndexNode([new ConstantNode(2), new SymbolNode('x')]),
new ConstantNode(3));
var c = new AssignmentNode(
new SymbolNode('B'),
new IndexNode([new ConstantNode(2), new SymbolNode('x')]),
new ConstantNode(3));
var d = new AssignmentNode(
new SymbolNode('A'),
new IndexNode([new ConstantNode(2)]),
new ConstantNode(3));
var e = new AssignmentNode(
new SymbolNode('A'),
new IndexNode([new ConstantNode(2), new SymbolNode('x')]),
new ConstantNode(4));
assert.strictEqual(a.equals(null), false);
assert.strictEqual(a.equals(undefined), false);
assert.strictEqual(a.equals(b), true);
assert.strictEqual(a.equals(c), false);
assert.strictEqual(a.equals(d), false);
assert.strictEqual(a.equals(e), false);
});
it ('should respect the \'all\' parenthesis option', function () {
var object = new SymbolNode('a');
var value = new ConstantNode(1);
var n = new AssignmentNode(object, value);
assert.equal(n.toString({parenthesis: 'all'}), 'a = (1)');
assert.equal(n.toTex({parenthesis: 'all'}), ' a:=\\left(1\\right)');
});
it ('should stringify a AssignmentNode', function () {
var object = new SymbolNode('b');
var value = new ConstantNode(3);
var n = new AssignmentNode(object, value);
assert.equal(n.toString(), 'b = 3');
});
it ('should stringify an AssignmentNode containing an AssignmentNode', function () {
var value = new ConstantNode(2);
var a = new AssignmentNode(new SymbolNode('a'), value);
var n = new AssignmentNode(new SymbolNode('b'), a);
assert.equal(n.toString(), 'b = (a = 2)');
});
it ('should stringify an AssignmentNode with custom toString', function () {
//Also checks if custom funcions get passed to the children
var customFunction = function (node, options) {
if (node.type === 'AssignmentNode') {
return node.object.toString(options) +
(node.index ? node.index.toString(options) : '') +
' equals ' + node.value.toString(options);
}
else if (node.type === 'ConstantNode') {
return 'const(' + node.value + ', ' + node.valueType + ')'
}
};
var object = new SymbolNode('a');
var value = new ConstantNode(1);
var n = new AssignmentNode(object, value);
assert.equal(n.toString({handler: customFunction}), 'a equals const(1, number)');
});
it ('should LaTeX a AssignmentNode', function () {
var value = new ConstantNode(2);
var a = new AssignmentNode(new SymbolNode('a'), value);
assert.equal(a.toTex(), ' a:=2');
});
it ('should LaTeX an AssignmentNode containing an AssignmentNode', function () {
var value = new ConstantNode(2);
var a = new AssignmentNode(new SymbolNode('a'), value);
var q = new AssignmentNode(new SymbolNode('q'), a);
assert.equal(q.toTex(), ' q:=\\left( a:=2\\right)');
});
it ('should LaTeX an AssignmentNode with custom toTex', function () {
//Also checks if custom funcions get passed to the children
var customFunction = function (node, options) {
if (node.isAssignmentNode) {
return node.object.toTex(options) +
(node.index ? node.index.toTex(options) : '') +
'\\mbox{equals}' + node.value.toTex(options);
}
else if (node.type === 'ConstantNode') {
return 'const\\left(' + node.value + ', ' + node.valueType + '\\right)'
}
};
var object = new SymbolNode('a');
var value = new ConstantNode(1);
var n = new AssignmentNode(object, value);
assert.equal(n.toTex({handler: customFunction}), ' a\\mbox{equals}const\\left(1, number\\right)');
});
});

View File

@@ -0,0 +1,330 @@
// test BlockNode
var assert = require('assert');
var approx = require('../../../tools/approx');
var math = require('../../../index');
var Node = math.expression.node.Node;
var ConstantNode = math.expression.node.ConstantNode;
var SymbolNode = math.expression.node.SymbolNode;
var RangeNode = math.expression.node.RangeNode;
var AssignmentNode = math.expression.node.AssignmentNode;
var OperatorNode = math.expression.node.OperatorNode;
var BlockNode = math.expression.node.BlockNode;
var ResultSet = math.type.ResultSet;
describe('BlockNode', function() {
it ('should create a BlockNode', function () {
var n = new BlockNode([]);
assert(n instanceof BlockNode);
assert(n instanceof Node);
assert.equal(n.type, 'BlockNode');
});
it ('should have isBlockNode', function () {
var node = new BlockNode([]);
assert(node.isBlockNode);
});
it ('should throw an error when calling without new operator', function () {
assert.throws(function () {BlockNode()}, SyntaxError);
});
it ('should throw an error when adding invalid blocks', function () {
assert.throws(function () {new BlockNode()}, /Array expected/);
assert.throws(function () {new BlockNode([2])}, /Property "node" must be a Node/);
assert.throws(function () {new BlockNode([{node: 2, visible:true}])}, /Property "node" must be a Node/);
assert.throws(function () {new BlockNode([{node: new Node(), visible: 2}])}, /Property "visible" must be a boolean/);
});
it ('should compile and evaluate a BlockNode', function () {
var n = new BlockNode([
{
node: new ConstantNode(5),
visible: true
},
{
node: new AssignmentNode(new SymbolNode('foo'), new ConstantNode(3)),
visible: false
},
{
node: new SymbolNode('foo'),
visible: true
}
]);
var scope = {};
assert.deepEqual(n.compile().eval(scope), new ResultSet([5, 3]));
assert.deepEqual(scope, {foo: 3});
});
it ('expressions should be visible by default', function () {
var n = new BlockNode([
{node: new ConstantNode(5)}
]);
assert.deepEqual(n.compile().eval(), new ResultSet([5]));
});
it ('should filter a BlockNode', function () {
var a = new ConstantNode(5);
var b2 = new ConstantNode(3);
var foo = new SymbolNode('foo');
var b = new AssignmentNode(foo, b2);
var c = new SymbolNode('foo');
var d = new BlockNode([
{node: a, visible: true},
{node: b, visible: false},
{node: c, visible: true}
]);
assert.deepEqual(d.filter(function (node) {return node instanceof BlockNode}), [d]);
assert.deepEqual(d.filter(function (node) {return node instanceof SymbolNode}), [foo, c]);
assert.deepEqual(d.filter(function (node) {return node instanceof RangeNode}), []);
assert.deepEqual(d.filter(function (node) {return node instanceof ConstantNode}), [a, b2]);
assert.deepEqual(d.filter(function (node) {return node instanceof ConstantNode && node.value == '3'}), [b2]);
});
it ('should run forEach on a BlockNode', function () {
// [x, 2]
var x = new SymbolNode('x');
var two = new ConstantNode(2);
var c = new OperatorNode('+', 'add', [two, x]);
var a = new BlockNode([
{node: x},
{node: c}
]);
var nodes = [];
var paths = [];
a.forEach(function (node, path, parent) {
nodes.push(node);
paths.push(path);
assert.strictEqual(parent, a);
});
assert.equal(nodes.length, 2);
assert.strictEqual(nodes[0], x);
assert.strictEqual(nodes[1], c);
assert.deepEqual(paths, ['blocks[0].node', 'blocks[1].node']);
});
it ('should map a BlockNode', function () {
// [x, 2]
var x = new SymbolNode('x');
var two = new ConstantNode(2);
var c = new OperatorNode('+', 'add', [two, x]);
var a = new BlockNode([
{node: x},
{node: c}
]);
var nodes = [];
var paths = [];
var d = new ConstantNode(3);
var e = a.map(function (node, path, parent) {
nodes.push(node);
paths.push(path);
assert.strictEqual(parent, a);
return node instanceof SymbolNode && node.name == 'x' ? d : node;
});
assert.equal(nodes.length, 2);
assert.strictEqual(nodes[0], x);
assert.strictEqual(nodes[1], c);
assert.deepEqual(paths, ['blocks[0].node', 'blocks[1].node']);
assert.notStrictEqual(e, a);
assert.strictEqual(e.blocks[0].node, d);
assert.strictEqual(e.blocks[1].node, c);
// should not touch nested nodes
assert.strictEqual(e.blocks[1].node.args[0], two);
assert.strictEqual(e.blocks[1].node.args[1], x);
});
it ('should throw an error when the map callback does not return a node', function () {
var x = new SymbolNode('x');
var two = new ConstantNode(2);
var c = new OperatorNode('+', 'add', [two, x]);
var a = new BlockNode([
{node: x},
{node: c}
]);
assert.throws(function () {
a.map(function () {});
}, /Callback function must return a Node/)
});
it ('should transform a BlockNodes parameters', function () {
// [x, 2]
var b = new SymbolNode('x');
var c = new ConstantNode(2);
var a = new BlockNode([
{node: b},
{node: c}
]);
var d = new ConstantNode(3);
var e = a.transform(function (node) {
return node instanceof SymbolNode && node.name == 'x' ? d : node;
});
assert.notStrictEqual(e, a);
assert.deepEqual(e.blocks[0].node, d);
assert.deepEqual(e.blocks[1].node, c);
});
it ('should transform a BlockNode itself', function () {
// [x, 2]
var a = new BlockNode([]);
var d = new ConstantNode(3);
var e = a.transform(function (node) {
return node instanceof BlockNode ? d : node;
});
assert.notStrictEqual(e, a);
assert.deepEqual(e, d);
});
it ('should traverse a BlockNode', function () {
var a = new ConstantNode(1);
var b = new ConstantNode(2);
var c = new BlockNode([
{node: a, visible: true},
{node: b, visible: true}
]);
var count = 0;
c.traverse(function (node, index, parent) {
count++;
switch(count) {
case 1:
assert.strictEqual(node, c);
assert.strictEqual(index, null);
assert.strictEqual(parent, null);
break;
case 2:
assert.strictEqual(node, a);
assert.strictEqual(index, 'blocks[0].node');
assert.strictEqual(parent, c);
break;
case 3:
assert.strictEqual(node, b);
assert.strictEqual(index, 'blocks[1].node');
assert.strictEqual(parent, c);
break;
}
});
assert.equal(count, 3);
});
it ('should clone a BlockNode', function () {
// [x, 2]
var b = new SymbolNode('x');
var c = new ConstantNode(2);
var a = new BlockNode([
{node: b},
{node: c}
]);
var d = a.clone();
assert(d instanceof BlockNode);
assert.deepEqual(a, d);
assert.notStrictEqual(a, d);
assert.notStrictEqual(a.blocks, d.blocks);
assert.notStrictEqual(a.blocks[0], d.blocks[0]);
assert.notStrictEqual(a.blocks[1], d.blocks[1]);
assert.strictEqual(a.blocks[0].node, d.blocks[0].node);
assert.strictEqual(a.blocks[1].node, d.blocks[1].node);
});
it ('test equality another Node', function () {
var a = new BlockNode([ {node: new SymbolNode('x')}, {node: new ConstantNode(2)} ]);
var b = new BlockNode([ {node: new SymbolNode('x')}, {node: new ConstantNode(2)} ]);
var c = new BlockNode([ {node: new SymbolNode('x')}, {node: new ConstantNode(4)} ]);
var d = new BlockNode([ {node: new SymbolNode('x')}, {node: new ConstantNode(2), visible: false} ]);
var e = new BlockNode([ {node: new SymbolNode('x')}, {node: new ConstantNode(2)}, {node: new ConstantNode(5)} ]);
assert.strictEqual(a.equals(null), false);
assert.strictEqual(a.equals(undefined), false);
assert.strictEqual(a.equals(b), true);
assert.strictEqual(a.equals(c), false);
assert.strictEqual(a.equals(d), false);
assert.strictEqual(a.equals(e), false);
});
it ('should stringify a BlockNode', function () {
var n = new BlockNode([
{node: new ConstantNode(5), visible:true},
{node: new AssignmentNode(new SymbolNode('foo'), new ConstantNode(3)), visible:false},
{node: new SymbolNode('foo'), visible:true}
]);
assert.equal(n.toString(), '5\nfoo = 3;\nfoo');
});
it ('should stringify a BlockNode with custom toString', function () {
//Also checks if the custom functions get passed on to the children
var customFunction = function (node, options) {
if (node.type === 'BlockNode') {
var string = '';
node.blocks.forEach(function (block) {
string += block.node.toString(options) + '; ';
});
return string;
}
else if (node.type === 'ConstantNode') {
return 'const(' + node.value + ', ' + node.valueType + ')'
}
};
var a = new ConstantNode(1);
var b = new ConstantNode(2);
var n = new BlockNode([{node: a}, {node: b}]);
assert.equal(n.toString({handler: customFunction}), 'const(1, number); const(2, number); ');
});
it ('should LaTeX a BlockNode', function () {
var n = new BlockNode([
{node: new ConstantNode(5), visible:true},
{node: new AssignmentNode(new SymbolNode('foo'), new ConstantNode(3)), visible:false},
{node: new SymbolNode('foo'), visible:true}
]);
assert.equal(n.toTex(), '5\\;\\;\n foo:=3;\\;\\;\n foo');
});
it ('should LaTeX a BlockNode with custom toTex', function () {
//Also checks if the custom functions get passed on to the children
var customFunction = function (node, options) {
if (node.type === 'BlockNode') {
var latex = '';
node.blocks.forEach(function (block) {
latex += block.node.toTex(options) + '; ';
});
return latex;
}
else if (node.type === 'ConstantNode') {
return 'const\\left(' + node.value + ', ' + node.valueType + '\\right)'
}
};
var a = new ConstantNode(1);
var b = new ConstantNode(2);
var n = new BlockNode([{node: a}, {node: b}]);
assert.equal(n.toTex({handler: customFunction}), 'const\\left(1, number\\right); const\\left(2, number\\right); ');
});
});

View File

@@ -0,0 +1,333 @@
// test ConditionalNode
var assert = require('assert');
var approx = require('../../../tools/approx');
var math = require('../../../index');
var Node = math.expression.node.Node;
var ConstantNode = math.expression.node.ConstantNode;
var SymbolNode = math.expression.node.SymbolNode;
var AssignmentNode = math.expression.node.AssignmentNode;
var ConditionalNode = math.expression.node.ConditionalNode;
describe('ConditionalNode', function() {
var condition = new ConstantNode(true);
var zero = new ConstantNode(0);
var one = new ConstantNode(1);
var two = new ConstantNode(2);
var three = new ConstantNode(3);
var a = new AssignmentNode(new SymbolNode('a'), two);
var b = new AssignmentNode(new SymbolNode('b'), three);
it ('should create a ConditionalNode', function () {
var n = new ConditionalNode(condition, a, b);
assert(n instanceof ConditionalNode);
assert(n instanceof Node);
assert.equal(n.type, 'ConditionalNode');
});
it ('should have isConditionalNode', function () {
var node = new ConditionalNode(condition, a, b);
assert(node.isConditionalNode);
});
it ('should throw an error when calling without new operator', function () {
assert.throws(function () {ConditionalNode()}, SyntaxError);
});
it ('should throw an error when creating without arguments', function () {
assert.throws(function () {new ConditionalNode()}, TypeError);
assert.throws(function () {new ConditionalNode(condition)}, TypeError);
assert.throws(function () {new ConditionalNode(condition, a)}, TypeError);
assert.throws(function () {new ConditionalNode(condition, null, b)}, TypeError);
});
it ('should lazy evaluate a ConditionalNode', function () {
var n = new ConditionalNode(condition, a, b);
var expr = n.compile();
var scope = {};
assert.equal(expr.eval(scope), 2);
assert.deepEqual(scope, {a: 2});
});
describe('evaluate', function () {
var condition = new ConditionalNode(new SymbolNode('a'), one, zero);
it('should evaluate boolean conditions', function() {
assert.equal(condition.compile().eval({a: true}), 1);
assert.equal(condition.compile().eval({a: false}), 0);
});
it('should evaluate number conditions', function() {
assert.equal(condition.compile().eval({a: 1}), 1);
assert.equal(condition.compile().eval({a: 4}), 1);
assert.equal(condition.compile().eval({a: -1}), 1);
assert.equal(condition.compile().eval({a: 0}), 0);
});
it('should evaluate bignumber conditions', function() {
assert.equal(condition.compile().eval({a: math.bignumber(1)}), 1);
assert.equal(condition.compile().eval({a: math.bignumber(4)}), 1);
assert.equal(condition.compile().eval({a: math.bignumber(-1)}), 1);
assert.equal(condition.compile().eval({a: math.bignumber(0)}), 0);
});
it('should evaluate complex number conditions', function() {
assert.equal(condition.compile().eval({a: math.complex(2, 3)}), 1);
assert.equal(condition.compile().eval({a: math.complex(2, 0)}), 1);
assert.equal(condition.compile().eval({a: math.complex(0, 3)}), 1);
assert.equal(condition.compile().eval({a: math.complex(0, 0)}), 0);
});
it('should evaluate string conditions', function() {
assert.equal(condition.compile().eval({a: 'hello'}), 1);
assert.equal(condition.compile().eval({a: ''}), 0);
});
it('should evaluate unit conditions', function() {
assert.equal(condition.compile().eval({a: math.unit('5cm')}), 1);
assert.equal(condition.compile().eval({a: math.unit('0 inch')}), 0);
assert.equal(condition.compile().eval({a: math.unit('meter')}), 0);
});
it('should evaluate null conditions', function() {
assert.equal(condition.compile().eval({a: null}), 0);
});
it('should evaluate undefined conditions', function() {
assert.equal(condition.compile().eval({a: undefined}), 0);
});
it('should throw an error in case of unsupported type of conditions', function() {
assert.throws(function () {condition.compile().eval({a: {}})});
assert.throws(function () {condition.compile().eval({a: []})});
assert.throws(function () {condition.compile().eval({a: math.matrix()})});
});
});
it ('should filter a ConditionalNode', function () {
var n = new ConditionalNode(condition, a, b);
assert.deepEqual(n.filter(function (node) {return node instanceof ConditionalNode}), [n]);
assert.deepEqual(n.filter(function (node) {return node instanceof ConstantNode}), [condition, two, three]);
assert.deepEqual(n.filter(function (node) {return node instanceof ConstantNode && node.value == '2'}), [two]);
});
it ('should run forEach on a ConditionalNode', function () {
var condition = new ConstantNode(1);
var a = new ConstantNode(2);
var b = new ConstantNode(3);
var n = new ConditionalNode(condition, a, b);
var nodes = [];
var paths = [];
n.forEach(function (node, path, parent) {
nodes.push(node);
paths.push(path);
assert.strictEqual(parent, n);
});
assert.equal(nodes.length, 3);
assert.strictEqual(nodes[0], condition);
assert.strictEqual(nodes[1], a);
assert.strictEqual(nodes[2], b);
assert.deepEqual(paths, ['condition', 'trueExpr', 'falseExpr']);
});
it ('should map a ConditionalNode', function () {
var condition = new ConstantNode(1);
var a = new ConstantNode(2);
var b = new ConstantNode(3);
var n = new ConditionalNode(condition, a, b);
var nodes = [];
var paths = [];
var e = new ConstantNode(4);
var f = n.map(function (node, path, parent) {
nodes.push(node);
paths.push(path);
assert.strictEqual(parent, n);
return node instanceof ConstantNode && node.value == '1' ? e : node;
});
assert.equal(nodes.length, 3);
assert.strictEqual(nodes[0], condition);
assert.strictEqual(nodes[1], a);
assert.strictEqual(nodes[2], b);
assert.deepEqual(paths, ['condition', 'trueExpr', 'falseExpr']);
assert.notStrictEqual(f, n);
assert.strictEqual(f.condition, e);
assert.strictEqual(f.trueExpr, a);
assert.strictEqual(f.falseExpr, b);
});
it ('should throw an error when the map callback does not return a node', function () {
var condition = new ConstantNode(1);
var a = new ConstantNode(2);
var b = new ConstantNode(3);
var n = new ConditionalNode(condition, a, b);
assert.throws(function () {
n.map(function () {});
}, /Callback function must return a Node/)
});
it ('should transform a ConditionalNodes condition', function () {
var condition = new ConstantNode(1);
var a = new ConstantNode(2);
var b = new ConstantNode(3);
var n = new ConditionalNode(condition, a, b);
var e = new ConstantNode(4);
var f = n.transform(function (node) {
return node instanceof ConstantNode && node.value == '1' ? e : node;
});
assert.notStrictEqual(f, n);
assert.deepEqual(f.condition, e);
assert.deepEqual(f.trueExpr, a);
assert.deepEqual(f.falseExpr, b);
});
it ('should transform a ConditionalNodes trueExpr', function () {
var condition = new ConstantNode(1);
var a = new ConstantNode(2);
var b = new ConstantNode(3);
var n = new ConditionalNode(condition, a, b);
var e = new ConstantNode(4);
var f = n.transform(function (node) {
return node instanceof ConstantNode && node.value == '2' ? e : node;
});
assert.notStrictEqual(f, n);
assert.deepEqual(f.condition, condition);
assert.deepEqual(f.trueExpr, e);
assert.deepEqual(f.falseExpr, b);
});
it ('should transform a ConditionalNodes falseExpr', function () {
var condition = new ConstantNode(1);
var a = new ConstantNode(2);
var b = new ConstantNode(3);
var n = new ConditionalNode(condition, a, b);
var e = new ConstantNode(4);
var f = n.transform(function (node) {
return node instanceof ConstantNode && node.value == '3' ? e : node;
});
assert.notStrictEqual(f, n);
assert.deepEqual(f.condition, condition);
assert.deepEqual(f.trueExpr, a);
assert.deepEqual(f.falseExpr, e);
});
it ('should transform a ConditionalNode itself', function () {
var condition = new ConstantNode(1);
var a = new ConstantNode(2);
var b = new ConstantNode(3);
var n = new ConditionalNode(condition, a, b);
var e = new ConstantNode(5);
var f = n.transform(function (node) {
return node instanceof ConditionalNode ? e : node;
});
assert.notStrictEqual(f, n);
assert.deepEqual(f, e);
});
it ('should clone a ConditionalNode itself', function () {
var condition = new ConstantNode(1);
var a = new ConstantNode(2);
var b = new ConstantNode(3);
var c = new ConditionalNode(condition, a, b);
var d = c.clone();
assert(d instanceof ConditionalNode);
assert.deepEqual(d, c);
assert.notStrictEqual(d, c);
assert.strictEqual(d.condition, c.condition);
assert.strictEqual(d.trueExpr, c.trueExpr);
assert.strictEqual(d.falseExpr, c.falseExpr);
});
it ('test equality another Node', function () {
var a = new ConditionalNode(new ConstantNode(1), new ConstantNode(2), new ConstantNode(3));
var b = new ConditionalNode(new ConstantNode(1), new ConstantNode(2), new ConstantNode(3));
var c = new ConditionalNode(new SymbolNode('x'), new ConstantNode(2), new ConstantNode(3));
var d = new ConditionalNode(new ConstantNode(1), new ConstantNode(5), new ConstantNode(3));
var e = new ConditionalNode(new ConstantNode(1), new ConstantNode(2), new ConstantNode(55));
assert.strictEqual(a.equals(null), false);
assert.strictEqual(a.equals(undefined), false);
assert.strictEqual(a.equals(b), true);
assert.strictEqual(a.equals(c), false);
assert.strictEqual(a.equals(d), false);
assert.strictEqual(a.equals(e), false);
});
it ('should respect the \'all\' parenthesis option', function () {
assert.equal(math.parse('a?b:c').toString({parenthesis: 'all'}), '(a) ? (b) : (c)');
});
it ('should stringify a ConditionalNode', function () {
var n = new ConditionalNode(condition, a, b);
assert.equal(n.toString(), 'true ? (a = 2) : (b = 3)');
});
it ('should stringify a ConditionalNode with custom toString', function () {
//Also checks if the custom functions get passed on to the children
var customFunction = function (node, options) {
if (node.type === 'ConditionalNode') {
return 'if ' + node.condition.toString(options)
+ ' then ' + node.trueExpr.toString(options)
+ ' else ' + node.falseExpr.toString(options);
}
else if (node.type === 'ConstantNode') {
return 'const(' + node.value + ', ' + node.valueType + ')'
}
};
var a = new ConstantNode(1);
var b = new ConstantNode(2);
var c = new ConstantNode(3);
var n = new ConditionalNode(a, b, c);
assert.equal(n.toString({handler: customFunction}), 'if const(1, number) then const(2, number) else const(3, number)');
});
it ('should LaTeX a ConditionalNode', function () {
var n = new ConditionalNode(condition, a, b);
// note that b is enclosed in \\mathrm{...} since it's a unit
assert.equal(n.toTex(), '\\begin{cases} { a:=2}, &\\quad{\\text{if }\\;true}\\\\{\\mathrm{b}:=3}, &\\quad{\\text{otherwise}}\\end{cases}');
});
it ('should LaTeX a ConditionalNode with custom toTex', function () {
//Also checks if the custom functions get passed on to the children
var customFunction = function (node, options) {
if (node.type === 'ConditionalNode') {
return 'if ' + node.condition.toTex(options)
+ ' then ' + node.trueExpr.toTex(options)
+ ' else ' + node.falseExpr.toTex(options);
}
else if (node.type === 'ConstantNode') {
return 'const\\left(' + node.value + ', ' + node.valueType + '\\right)'
}
};
var a = new ConstantNode(1);
var b = new ConstantNode(2);
var c = new ConstantNode(3);
var n = new ConditionalNode(a, b, c);
assert.equal(n.toTex({handler: customFunction}), 'if const\\left(1, number\\right) then const\\left(2, number\\right) else const\\left(3, number\\right)');
});
});

View File

@@ -0,0 +1,191 @@
// test ConstantNode
var assert = require('assert');
var approx = require('../../../tools/approx');
var math = require('../../../index');
var bigmath = require('../../../index').create({number: 'BigNumber'});
var Node = math.expression.node.Node;
var ConstantNode = math.expression.node.ConstantNode;
var SymbolNode = math.expression.node.SymbolNode;
describe('ConstantNode', function() {
it ('should create a ConstantNode with value type', function () {
var a = new ConstantNode('3', 'number');
assert(a instanceof Node);
assert.equal(a.type, 'ConstantNode');
});
it ('should create a ConstantNode without value type', function () {
var a = new ConstantNode(3);
assert(a instanceof Node);
assert.equal(a.type, 'ConstantNode');
// TODO: extensively test each of the supported types
assert.deepEqual(new ConstantNode(3), new ConstantNode('3', 'number'));
assert.deepEqual(new ConstantNode('hello'), new ConstantNode('hello', 'string'));
assert.deepEqual(new ConstantNode(true), new ConstantNode('true', 'boolean'));
assert.deepEqual(new ConstantNode(false), new ConstantNode('false', 'boolean'));
assert.deepEqual(new ConstantNode(null), new ConstantNode('null', 'null'));
assert.deepEqual(new ConstantNode(undefined), new ConstantNode('undefined', 'undefined'));
});
it ('should have isConstantNode', function () {
var node = new ConstantNode(1);
assert(node.isConstantNode);
});
it ('should throw an error when calling without new operator', function () {
assert.throws(function () {ConstantNode('3', 'number')}, SyntaxError);
});
it ('should throw an error in case of wrong construction arguments', function () {
assert.throws(function () {new ConstantNode(3, 'number');}, TypeError);
assert.throws(function () {new ConstantNode(new Date());}, TypeError);
assert.throws(function () {new ConstantNode('3', Number);}, TypeError);
});
it ('should throw an error in case of unknown type of constant', function () {
assert.throws(function () {new ConstantNode('3', 'bla').compile();}, TypeError);
});
it ('should compile a ConstantNode', function () {
var expr = new ConstantNode('2.3', 'number').compile();
assert.strictEqual(expr.eval(), 2.3);
expr = new ConstantNode('002.3', 'number').compile();
assert.strictEqual(expr.eval(), 2.3);
expr = new ConstantNode('hello', 'string').compile();
assert.strictEqual(expr.eval(), 'hello');
expr = new ConstantNode('true', 'boolean').compile();
assert.strictEqual(expr.eval(), true);
expr = new ConstantNode('undefined', 'undefined').compile();
assert.strictEqual(expr.eval(), undefined);
expr = new ConstantNode('null', 'null').compile();
assert.strictEqual(expr.eval(), null);
});
it ('should compile a ConstantNode with bigmath', function () {
var expr = new bigmath.expression.node.ConstantNode('2.3', 'number').compile();
assert.deepEqual(expr.eval(), new bigmath.type.BigNumber(2.3));
});
it ('should find a ConstantNode', function () {
var a = new ConstantNode('2', 'number');
assert.deepEqual(a.filter(function (node) {return node instanceof ConstantNode}), [a]);
assert.deepEqual(a.filter(function (node) {return node instanceof SymbolNode}), []);
});
it ('should run forEach on a ConstantNode', function () {
var a = new ConstantNode(2);
a.forEach(function () {
assert.ok(false, 'should not execute, constant has no childs')
});
});
it ('should map a ConstantNode', function () {
var a = new ConstantNode(2);
var b = a.map(function () {
assert.ok(false, 'should not execute, constant has no childs')
});
assert.notStrictEqual(b, a);
assert.deepEqual(b, a);
});
it ('should transform a ConstantNode', function () {
var a = new ConstantNode(2);
var b = new ConstantNode(3);
var c = a.transform(function (node) {
return node instanceof ConstantNode && node.value == '2' ? b : node;
});
assert.deepEqual(c, b);
// no match should leave the node as is
var d = a.transform(function (node) {
return node instanceof ConstantNode && node.value == '99' ? b : node;
});
assert.notStrictEqual(d, a);
assert.deepEqual(d, a);
});
it ('should clone a ConstantNode', function () {
var a = new ConstantNode(2);
var b = a.clone();
assert(b instanceof ConstantNode);
assert.deepEqual(a, b);
assert.notStrictEqual(a, b);
assert.equal(a.value, b.value);
assert.equal(a.valueType, b.valueType);
});
it ('test equality another Node', function () {
var a = new ConstantNode(2);
assert.strictEqual(a.equals(null), false);
assert.strictEqual(a.equals(undefined), false);
assert.strictEqual(a.equals(new ConstantNode(2)), true);
assert.strictEqual(a.equals(new ConstantNode(3)), false);
assert.strictEqual(a.equals(new ConstantNode('2', 'number')), true);
assert.strictEqual(a.equals(new ConstantNode('2', 'string')), false);
assert.strictEqual(a.equals(new SymbolNode('2')), false);
assert.strictEqual(a.equals({value:2, valueType: 'number'}), false);
});
it ('should stringify a ConstantNode', function () {
assert.equal(new ConstantNode('3', 'number').toString(), '3');
assert.deepEqual(new ConstantNode('3', 'number').toString(), '3');
assert.equal(new ConstantNode('hi', 'string').toString(), '"hi"');
assert.equal(new ConstantNode('true', 'boolean').toString(), 'true');
assert.equal(new ConstantNode('false', 'boolean').toString(), 'false');
assert.equal(new ConstantNode('undefined', 'undefined').toString(), 'undefined');
assert.equal(new ConstantNode('null', 'null').toString(), 'null');
});
it ('should stringify a ConstantNode with custom toString', function () {
//Also checks if the custom functions get passed on to the children
var customFunction = function (node, options) {
if (node.type === 'ConstantNode') {
return 'const(' + node.value + ', ' + node.valueType + ')'
}
};
var n = new ConstantNode(1);
assert.equal(n.toString({handler: customFunction}), 'const(1, number)');
});
it ('should LaTeX a ConstantNode', function () {
assert.equal(new ConstantNode('3', 'number').toTex(), '3');
assert.deepEqual(new ConstantNode('3', 'number').toTex(), '3');
assert.equal(new ConstantNode('hi', 'string').toTex(), '\\mathtt{"hi"}');
assert.equal(new ConstantNode('true', 'boolean').toTex(), 'true');
assert.equal(new ConstantNode('false', 'boolean').toTex(), 'false');
assert.equal(new ConstantNode('undefined', 'undefined').toTex(), 'undefined');
assert.equal(new ConstantNode('null', 'null').toTex(), 'null');
});
it ('should LaTeX a ConstantNode in exponential notation', function () {
var n = new ConstantNode('1e10', 'number');
assert.equal(n.toTex(), '1\\cdot10^{10}');
});
it ('should LaTeX a ConstantNode with custom toTex', function () {
//Also checks if the custom functions get passed on to the children
var customFunction = function (node, options) {
if (node.type === 'ConstantNode') {
return 'const\\left(' + node.value + ', ' + node.valueType + '\\right)'
}
};
var n = new ConstantNode(1);
assert.equal(n.toTex({handler: customFunction}), 'const\\left(1, number\\right)');
});
});

View File

@@ -0,0 +1,438 @@
// test FunctionAssignmentNode
var assert = require('assert');
var approx = require('../../../tools/approx');
var math = require('../../../index').create();
var Node = math.expression.node.Node;
var ConstantNode = math.expression.node.ConstantNode;
var SymbolNode = math.expression.node.SymbolNode;
var AssignmentNode = math.expression.node.AssignmentNode;
var ConditionalNode = math.expression.node.ConditionalNode;
var OperatorNode = math.expression.node.OperatorNode;
var FunctionNode = math.expression.node.FunctionNode;
var FunctionAssignmentNode = math.expression.node.FunctionAssignmentNode;
var RangeNode = math.expression.node.RangeNode;
describe('FunctionAssignmentNode', function() {
it ('should create a FunctionAssignmentNode', function () {
var n = new FunctionAssignmentNode('f', ['x'], new ConstantNode(2));
assert(n instanceof FunctionAssignmentNode);
assert(n instanceof Node);
assert.equal(n.type, 'FunctionAssignmentNode');
});
it ('should have isFunctionAssignmentNode', function () {
var node = new FunctionAssignmentNode('f', ['x'], new ConstantNode(2));
assert(node.isFunctionAssignmentNode);
});
it ('should throw an error when calling without new operator', function () {
assert.throws(function () {FunctionAssignmentNode('f', ['x'], new ConstantNode(2))}, SyntaxError);
});
it ('should throw an error on wrong constructor arguments', function () {
assert.throws(function () {new FunctionAssignmentNode()}, TypeError);
assert.throws(function () {new FunctionAssignmentNode('a')}, TypeError);
assert.throws(function () {new FunctionAssignmentNode('a', ['x'])}, TypeError);
assert.throws(function () {new FunctionAssignmentNode(null, ['x'], new ConstantNode(2))}, TypeError);
});
it ('should compile a FunctionAssignmentNode', function () {
var a = new ConstantNode(2);
var x = new SymbolNode('x');
var o = new OperatorNode('+', 'add', [a, x]);
var n = new FunctionAssignmentNode('f', ['x'], o);
var expr = n.compile();
var scope = {};
var f = expr.eval(scope);
assert.equal(typeof scope.f, 'function');
assert.equal(scope.f(3), 5);
assert.equal(scope.f(5), 7);
});
it ('should compile a typed FunctionAssignmentNode', function () {
var a = new ConstantNode(2);
var x = new SymbolNode('x');
var o = new OperatorNode('+', 'add', [a, x]);
var n = new FunctionAssignmentNode('f', [{name: 'x', type: 'number' }], o);
var expr = n.compile();
var scope = {};
var f = expr.eval(scope);
assert.equal(typeof scope.f, 'function');
assert.equal(scope.f(3), 5);
assert.equal(scope.f(5), 7);
assert.throws(function () { scope.f(new Date())}, /Unexpected type of argument in function f/);
assert.throws(function () { scope.f(2, 2)}, /Too many arguments in function f/);
assert.throws(function () { scope.f()}, /Too few arguments in function f/);
});
it ('should eval a recursive FunctionAssignmentNode', function () {
var x = new SymbolNode('x');
var one = new ConstantNode(1);
var condition = new OperatorNode('<=', 'smallerEq', [x, one]);
var truePart = one;
var falsePart = new OperatorNode('*', 'multiply', [
x,
new FunctionNode(new SymbolNode('factorial'), [
new OperatorNode('-', 'subtract', [
x,
one
])
])
]);
var n1 = new ConditionalNode(condition, truePart, falsePart);
var n2 = new FunctionAssignmentNode('factorial', ['x'], n1);
var expr = n2.compile();
var scope = {};
var factorial = expr.eval(scope);
assert.equal(typeof scope.factorial, 'function');
assert.equal(factorial(3), 6);
assert.equal(factorial(5), 120);
});
it ('should eval a recursive FunctionAssignmentNode with two recursive calls', function () {
var x = new SymbolNode('x');
var zero = new ConstantNode(0);
var one = new ConstantNode(1);
var two = new ConstantNode(2);
var n1 = new ConditionalNode(
new OperatorNode('<=', 'smallerEq', [x, zero]),
zero,
new ConditionalNode(
new OperatorNode('<=', 'smallerEq', [x, two]),
one,
new OperatorNode('+', 'add', [
new FunctionNode(new SymbolNode('fib'), [
new OperatorNode('-', 'subtract', [ x, one ])
]),
new FunctionNode(new SymbolNode('fib'), [
new OperatorNode('-', 'subtract', [ x, two ])
])
])
)
);
var n2 = new FunctionAssignmentNode('fib', ['x'], n1);
//var n2 = math.parse('fib(x) = (x <= 0) ? 0 : ((x <= 2) ? 1 : (fib(x - 1) + f(fib - 2)))');
var expr = n2.compile();
var scope = {};
var fib = expr.eval(scope);
assert.equal(typeof fib, 'function');
assert.equal(fib(0), 0);
assert.equal(fib(1), 1);
assert.equal(fib(2), 1);
assert.equal(fib(3), 2);
assert.equal(fib(4), 3);
assert.equal(fib(5), 5);
assert.equal(fib(6), 8);
assert.equal(fib(7), 13);
assert.equal(fib(8), 21);
});
it ('should pass function arguments in scope to functions with rawArgs', function () {
var outputScope = function (args, math, scope) {
return scope;
}
outputScope.rawArgs = true;
math.import({ outputScope: outputScope }, { override: true });
// f(x) = outputScope(x)
var x = new SymbolNode('x');
var o = new FunctionNode('outputScope', [x]);
var n = new FunctionAssignmentNode('f', ['x'], o);
var scope = {a: 2};
var f = n.eval(scope);
assert.deepEqual(f(3), {a: 2, f: f, x: 3});
});
it ('should pass function arguments in scope to functions with rawArgs returned by another function', function () {
var outputScope = function (args, math, scope) {
return scope;
}
outputScope.rawArgs = true;
var returnOutputScope = function () {
return outputScope
}
math.import({
outputScope: outputScope,
returnOutputScope: returnOutputScope
}, { override: true });
// f(x, y) = returnOutputScope(x)(y)
var a = new FunctionNode('returnOutputScope', [new SymbolNode('x')]);
var b = new FunctionNode(a, [new SymbolNode('y')]);
var n = new FunctionAssignmentNode('f', ['x', 'y'], b);
var scope = {a: 2};
var f = n.eval(scope);
assert.deepEqual(f(3, 4), {a: 2, f: f, x: 3, y: 4});
});
it ('should pass function arguments in scope to functions with rawArgs and transform', function () {
var outputScope = function (x) {
return 'should not occur'
}
outputScope.transform = function (args, math, scope) {
return scope;
}
outputScope.transform.rawArgs = true;
math.import({ outputScope: outputScope }, { override: true });
// f(x) = outputScope(x)
var x = new SymbolNode('x');
var o = new FunctionNode('outputScope', [x]);
var n = new FunctionAssignmentNode('f', ['x'], o);
var scope = {a: 2};
var f = n.eval(scope);
assert.deepEqual(f(3), {a: 2, f: f, x: 3});
});
it ('should filter a FunctionAssignmentNode', function () {
var a = new ConstantNode(2);
var x = new SymbolNode('x');
var o = new OperatorNode('+', 'add', [a, x]);
var n = new FunctionAssignmentNode('f', ['x'], o);
assert.deepEqual(n.filter(function (node) {return node instanceof FunctionAssignmentNode}), [n]);
assert.deepEqual(n.filter(function (node) {return node instanceof SymbolNode}), [x]);
assert.deepEqual(n.filter(function (node) {return node instanceof RangeNode}), []);
assert.deepEqual(n.filter(function (node) {return node instanceof ConstantNode}), [a]);
assert.deepEqual(n.filter(function (node) {return node instanceof ConstantNode && node.value == '2'}), [a]);
assert.deepEqual(n.filter(function (node) {return node instanceof ConstantNode && node.value == '4'}), []);
});
it ('should throw an error when creating a FunctionAssignmentNode with a reserved keyword', function () {
assert.throws(function () {
new FunctionAssignmentNode('end', ['x'], new ConstantNode(2));
}, /Illegal function name/)
});
it ('should filter a FunctionAssignmentNode without expression', function () {
var e = new FunctionAssignmentNode('f', ['x'], new ConstantNode(2));
assert.deepEqual(e.filter(function (node) {return node instanceof FunctionAssignmentNode}), [e]);
assert.deepEqual(e.filter(function (node) {return node instanceof SymbolNode}), []);
});
it ('should run forEach on a FunctionAssignmentNode', function () {
var a = new ConstantNode(2);
var n = new FunctionAssignmentNode('f', ['x'], a);
var nodes = [];
var paths = [];
n.forEach(function (node, path, parent) {
nodes.push(node);
paths.push(path);
assert.strictEqual(parent, n);
});
assert.equal(nodes.length, 1);
assert.strictEqual(nodes[0], a);
assert.deepEqual(paths, ['expr']);
});
it ('should map a FunctionAssignmentNode', function () {
var a = new ConstantNode(2);
var n = new FunctionAssignmentNode('f', ['x'], a);
var nodes = [];
var paths = [];
var e = new ConstantNode(3);
var f = n.map(function (node, path, parent) {
nodes.push(node);
paths.push(path);
assert.strictEqual(parent, n);
return node instanceof SymbolNode && node.name == 'x' ? e : node;
});
assert.equal(nodes.length, 1);
assert.strictEqual(nodes[0], a);
assert.deepEqual(paths, ['expr']);
assert.notStrictEqual(f, n);
assert.deepEqual(f.expr, a);
});
it ('should throw an error when the map callback does not return a node', function () {
var a = new ConstantNode(2);
var n = new FunctionAssignmentNode('f', ['x'], a);
assert.throws(function () {
n.map(function () {});
}, /Callback function must return a Node/)
});
it ('should transform a FunctionAssignmentNodes (nested) parameters', function () {
// f(x) = 2 + x
var a = new ConstantNode(2);
var x = new SymbolNode('x');
var c = new OperatorNode('+', 'add', [a, x]);
var n = new FunctionAssignmentNode('f', ['x'], c);
var e = new ConstantNode(3);
var f = n.transform(function (node) {
return node instanceof SymbolNode && node.name == 'x' ? e : node;
});
assert.notStrictEqual(f, n);
assert.deepEqual(f.expr.args[0], a);
assert.deepEqual(f.expr.args[1], e);
});
it ('should transform a FunctionAssignmentNode itself', function () {
// f(x) = 2 + x
var a = new ConstantNode(2);
var x = new SymbolNode('x');
var c = new OperatorNode('+', 'add', [a, x]);
var n = new FunctionAssignmentNode('f', ['x'], c);
var e = new ConstantNode(5);
var f = n.transform(function (node) {
return node instanceof FunctionAssignmentNode ? e : node;
});
assert.notStrictEqual(f, n);
assert.deepEqual(f, e);
});
it ('should clone a FunctionAssignmentNode', function () {
// f(x) = 2 + x
var a = new ConstantNode(2);
var x = new SymbolNode('x');
var c = new OperatorNode('+', 'add', [a, x]);
var d = new FunctionAssignmentNode('f', ['x'], c);
var e = d.clone();
assert(e instanceof FunctionAssignmentNode);
assert.deepEqual(e, d);
assert.notStrictEqual(e, d);
assert.strictEqual(e.expr, d.expr);
});
it ('test equality another Node', function () {
var a = new FunctionAssignmentNode('f', ['x'],
new OperatorNode('+', 'add', [new ConstantNode(2), new SymbolNode('x')]));
var b = new FunctionAssignmentNode('f', ['x'],
new OperatorNode('+', 'add', [new ConstantNode(2), new SymbolNode('x')]));
var c = new FunctionAssignmentNode('g', ['x'],
new OperatorNode('+', 'add', [new ConstantNode(2), new SymbolNode('x')]));
var d = new FunctionAssignmentNode('f', ['y'],
new OperatorNode('+', 'add', [new ConstantNode(2), new SymbolNode('x')]));
var e = new FunctionAssignmentNode('f', ['x'],
new OperatorNode('+', 'add', [new ConstantNode(3), new SymbolNode('x')]));
var f = new SymbolNode('add');
assert.strictEqual(a.equals(null), false);
assert.strictEqual(a.equals(undefined), false);
assert.strictEqual(a.equals(b), true);
assert.strictEqual(a.equals(c), false);
assert.strictEqual(a.equals(d), false);
assert.strictEqual(a.equals(e), false);
assert.strictEqual(a.equals(f), false);
});
it ('should respect the \'all\' parenthesis option', function () {
var expr = math.parse('f(x)=x+1');
assert.equal(expr.toString({parenthesis: 'all'}), 'f(x) = (x + 1)');
assert.equal(expr.toTex({parenthesis: 'all'}), '\\mathrm{f}\\left(x\\right):=\\left( x+1\\right)');
});
it ('should stringify a FunctionAssignmentNode', function () {
var a = new ConstantNode(2);
var x = new SymbolNode('x');
var o = new OperatorNode('+', 'add', [a, x]);
var n = new FunctionAssignmentNode('f', ['x'], o);
assert.equal(n.toString(), 'f(x) = 2 + x');
});
it ('should stringify a FunctionAssignmentNode conataining an AssignmentNode', function () {
var a = new ConstantNode(2);
var n1 = new AssignmentNode(new SymbolNode('a'), a);
var n = new FunctionAssignmentNode('f', ['x'], n1);
assert.equal(n.toString(), 'f(x) = (a = 2)');
});
it ('should stringify a FunctionAssignmentNode with custom toString', function () {
//Also checks if the custom functions get passed on to the children
var customFunction = function (node, options) {
if (node.type === 'FunctionAssignmentNode') {
var string = '[' + node.name + '](';
node.params.forEach(function (param) {
string += param + ', ';
});
string += ')=' + node.expr.toString(options);
return string;
}
else if (node.type === 'ConstantNode') {
return 'const(' + node.value + ', ' + node.valueType + ')'
}
};
var a = new ConstantNode(1);
var n = new FunctionAssignmentNode('func', ['x'], a);
assert.equal(n.toString({handler: customFunction}), '[func](x, )=const(1, number)');
});
it ('should LaTeX a FunctionAssignmentNode', function() {
var a = new ConstantNode(2);
var x = new SymbolNode('x');
var o = new OperatorNode('/', 'divide', [x, a]);
var p = new OperatorNode('^', 'pow', [o, a]);
var n = new FunctionAssignmentNode('f', ['x'], p);
assert.equal(n.toTex(), '\\mathrm{f}\\left(x\\right):=\\left({\\frac{ x}{2}}\\right)^{2}');
});
it ('should LaTeX a FunctionAssignmentNode containing an AssignmentNode', function () {
var a = new ConstantNode(2);
var n1 = new AssignmentNode(new SymbolNode('a'), a);
var n = new FunctionAssignmentNode('f', ['x'], n1);
assert.equal(n.toTex(), '\\mathrm{f}\\left(x\\right):=\\left( a:=2\\right)');
});
it ('should LaTeX a FunctionAssignmentNode with custom toTex', function () {
//Also checks if the custom functions get passed on to the children
var customFunction = function (node, options) {
if (node.type === 'FunctionAssignmentNode') {
var latex = '\\mbox{' + node.name + '}\\left(';
node.params.forEach(function (param) {
latex += param + ', ';
});
latex += '\\right)=' + node.expr.toTex(options);
return latex;
}
else if (node.type === 'ConstantNode') {
return 'const\\left(' + node.value + ', ' + node.valueType + '\\right)'
}
};
var a = new ConstantNode(1);
var n = new FunctionAssignmentNode('func', ['x'], a);
assert.equal(n.toTex({handler: customFunction}), '\\mbox{func}\\left(x, \\right)=const\\left(1, number\\right)');
});
});

View File

@@ -0,0 +1,583 @@
// test FunctionNode
var assert = require('assert');
var approx = require('../../../tools/approx');
var math = require('../../../index').create();
var Node = math.expression.node.Node;
var ConstantNode = math.expression.node.ConstantNode;
var SymbolNode = math.expression.node.SymbolNode;
var FunctionNode = math.expression.node.FunctionNode;
var OperatorNode = math.expression.node.OperatorNode;
var RangeNode = math.expression.node.RangeNode;
var IndexNode = math.expression.node.IndexNode;
var AccessorNode = math.expression.node.AccessorNode;
describe('FunctionNode', function() {
it ('should create a FunctionNode', function () {
var c = new ConstantNode(4);
var n = new FunctionNode(new SymbolNode('sqrt'), [c]);
assert(n instanceof FunctionNode);
assert(n instanceof Node);
assert.equal(n.type, 'FunctionNode');
});
it ('should have isFunctionNode', function () {
var c = new ConstantNode(1);
var node = new FunctionNode(new SymbolNode('square'), [c]);
assert(node.isFunctionNode);
});
it ('should throw an error when calling without new operator', function () {
var s = new SymbolNode('sqrt');
var c = new ConstantNode(4);
assert.throws(function () {FunctionNode(s, [c])}, SyntaxError);
});
it ('should throw an error when calling with wrong arguments', function () {
var s = new SymbolNode('sqrt');
var c = new ConstantNode(4);
assert.throws(function () {new FunctionNode(new Date(), [])}, TypeError);
assert.throws(function () {new FunctionNode(s, [2, 3])}, TypeError);
assert.throws(function () {new FunctionNode(s, [c, 3])}, TypeError);
});
it ('should get the name of a FunctionNode', function () {
var n1 = new FunctionNode(new SymbolNode('sqrt'), [new ConstantNode(4)]);
assert.equal(n1.name, 'sqrt');
var n = new AccessorNode(new SymbolNode('a'), new IndexNode([new ConstantNode('toString')]));
var n2 = new FunctionNode(n, [new ConstantNode(4)]);
assert.equal(n2.name, 'toString');
var n3 = new FunctionNode(new OperatorNode('+', 'add', []), [new ConstantNode(4)]);
assert.equal(n3.name, '');
});
it ('should compile a FunctionNode', function () {
var s = new SymbolNode('sqrt');
var c = new ConstantNode(4);
var n = new FunctionNode(s, [c]);
var scope = {};
assert.equal(n.compile().eval(scope), 2);
});
it ('should compile a FunctionNode containing an index', function () {
var s = new SymbolNode('foo');
var range = [new ConstantNode('bar')];
var i = new IndexNode(range);
var a = new AccessorNode(s, i);
var c = new ConstantNode(4);
var n = new FunctionNode(a, [c]);
var scope = {
foo: {
bar: function (x) {
return x * x;
}
}
};
assert.equal(n.compile().eval(scope), 16);
});
it ('should execute a FunctionNode with the right context', function () {
var s = new SymbolNode('foo');
var i = new IndexNode([new ConstantNode('getCount')]);
var a = new AccessorNode(s, i);
var c = new ConstantNode(4);
var n = new FunctionNode(a, [c]);
var scope = {
foo: {
count: 42,
getCount: function () {
return this.count;
}
}
};
assert.equal(n.compile().eval(scope), 42);
});
it ('should compile a FunctionNode with a raw function', function () {
var mymath = math.create();
function myFunction (args, _math, _scope) {
assert.equal(args.length, 2);
assert(args[0] instanceof mymath.expression.node.Node);
assert(args[1] instanceof mymath.expression.node.Node);
assert.deepEqual(_math.__proto__, mymath);
assert.deepEqual(_scope, scope);
return 'myFunction(' + args.join(', ') + ')';
}
myFunction.rawArgs = true;
mymath.import({myFunction: myFunction});
var s = new SymbolNode('myFunction');
var a = new mymath.expression.node.ConstantNode(4);
var b = new mymath.expression.node.ConstantNode(5);
var n = new mymath.expression.node.FunctionNode(s, [a, b]);
var scope = {};
assert.equal(n.compile().eval(scope), 'myFunction(4, 5)');
});
it ('should compile a FunctionNode containing an index resolving to a function with rawArgs', function () {
var mymath = math.create();
function myFunction (args, _math, _scope) {
assert.equal(args.length, 2);
assert(args[0] instanceof mymath.expression.node.Node);
assert(args[1] instanceof mymath.expression.node.Node);
assert.deepEqual(_math.__proto__, mymath);
assert.deepEqual(_scope, scope);
return 'myFunction(' + args.join(', ') + ')';
}
myFunction.rawArgs = true;
var obj = new SymbolNode('obj');
var prop = new ConstantNode('myFunction');
var i = new IndexNode([prop]);
var a = new AccessorNode(obj, i);
var b = new mymath.expression.node.ConstantNode(4);
var c = new mymath.expression.node.ConstantNode(5);
var n = new mymath.expression.node.FunctionNode(a, [b, c]);
var scope = {
obj: {
myFunction: myFunction
}
};
assert.equal(n.compile().eval(scope), 'myFunction(4, 5)');
});
it ('should compile a FunctionNode with overloaded a raw function', function () {
var mymath = math.create();
function myFunction (args, _math, _scope) {
assert.ok(false, 'should not be executed');
}
myFunction.rawArgs = true;
mymath.import({myFunction: myFunction});
var s = new SymbolNode('myFunction');
var a = new mymath.expression.node.ConstantNode(4);
var b = new mymath.expression.node.ConstantNode(5);
var n = new mymath.expression.node.FunctionNode(s, [a, b]);
var scope = {
myFunction: function () {
return 42;
}
};
assert.equal(n.compile().eval(scope), 42);
});
it ('should filter a FunctionNode', function () {
var s = new SymbolNode('a');
var b = new ConstantNode(2);
var c = new ConstantNode(1);
var n = new FunctionNode(s, [b, c]);
assert.deepEqual(n.filter(function (node) {return node instanceof FunctionNode}), [n]);
assert.deepEqual(n.filter(function (node) {return node instanceof RangeNode}), []);
assert.deepEqual(n.filter(function (node) {return node instanceof ConstantNode}), [b, c]);
assert.deepEqual(n.filter(function (node) {return node instanceof ConstantNode && node.value == '2'}), [b]);
assert.deepEqual(n.filter(function (node) {return node instanceof ConstantNode && node.value == '4'}), []);
});
it ('should run forEach on a FunctionNode', function () {
// multiply(x + 2, x)
var s = new SymbolNode('multiply');
var a = new SymbolNode('x');
var b = new ConstantNode(2);
var c = new OperatorNode('+', 'add', [a, b]);
var d = new SymbolNode('x');
var f = new FunctionNode(s, [c, d]);
var nodes = [];
var paths = [];
f.forEach(function (node, path, parent) {
nodes.push(node);
paths.push(path);
assert.strictEqual(parent, f);
});
assert.equal(nodes.length, 2);
assert.strictEqual(nodes[0], c);
assert.strictEqual(nodes[1], d);
assert.deepEqual(paths, ['args[0]', 'args[1]']);
});
it ('should map a FunctionNode', function () {
// multiply(x + 2, x)
var s = new SymbolNode('multiply');
var a = new SymbolNode('x');
var b = new ConstantNode(2);
var c = new OperatorNode('+', 'add', [a, b]);
var d = new SymbolNode('x');
var f = new FunctionNode(s, [c, d]);
var nodes = [];
var paths = [];
var g = new ConstantNode(3);
var h = f.map(function (node, path, parent) {
nodes.push(node);
paths.push(path);
assert.strictEqual(parent, f);
return node instanceof SymbolNode && node.name == 'x' ? g : node;
});
assert.equal(nodes.length, 2);
assert.strictEqual(nodes[0], c);
assert.strictEqual(nodes[1], d);
assert.deepEqual(paths, ['args[0]', 'args[1]']);
assert.notStrictEqual(h, f);
assert.strictEqual(h.args[0], c);
assert.strictEqual(h.args[0].args[0], a);
assert.strictEqual(h.args[0].args[1], b);
assert.equal(h.fn.name, 'multiply');
assert.strictEqual(h.args[1], g);
});
it ('should throw an error when the map callback does not return a node', function () {
var s = new SymbolNode('factorial');
var b = new ConstantNode(2);
var f = new FunctionNode(s, [b]);
assert.throws(function () {
f.map(function () {});
}, /Callback function must return a Node/)
});
it ('should transform a FunctionNodes (nested) parameters', function () {
// multiply(x + 2, x)
var s = new SymbolNode('multiply');
var a = new SymbolNode('x');
var b = new ConstantNode(2);
var c = new OperatorNode('+', 'add', [a, b]);
var d = new SymbolNode('x');
var f = new FunctionNode(s, [c, d]);
var g = new ConstantNode(3);
var h = f.transform(function (node) {
return node instanceof SymbolNode && node.name == 'x' ? g : node;
});
assert.notStrictEqual(h, f);
assert.deepEqual(h.args[0].args[0], g);
assert.deepEqual(h.args[0].args[1], b);
assert.deepEqual(h.name, 'multiply');
assert.deepEqual(h.args[1], g);
});
it ('should transform a FunctionNodes name', function () {
// add(2, 3)
var s = new SymbolNode('add');
var b = new ConstantNode(2);
var c = new ConstantNode(3);
var d = new FunctionNode(s, [b, c]);
var f = d.transform(function (node) {
if (node instanceof FunctionNode) {
node.fn = new SymbolNode('subtract');
}
return node;
});
assert.notStrictEqual(f, d);
assert.deepEqual(f.name, 'subtract');
});
it ('should transform a FunctionNode itself', function () {
// add(2, 3)
var s = new SymbolNode('add');
var b = new ConstantNode(2);
var c = new ConstantNode(3);
var d = new FunctionNode(s, [b, c]);
var e = new ConstantNode(5);
var f = d.transform(function (node) {
return node instanceof FunctionNode ? e : node;
});
assert.deepEqual(f, e);
});
it ('should traverse a FunctionNode', function () {
// add(2, 3)
var s = new SymbolNode('add');
var b = new ConstantNode(2);
var c = new ConstantNode(3);
var d = new FunctionNode(s, [b, c]);
var count = 0;
d.traverse(function (node, path, parent) {
count++;
switch(count) {
case 1:
assert.strictEqual(node, d);
assert.strictEqual(path, null);
assert.strictEqual(parent, null);
break;
case 2:
assert.strictEqual(node, b);
assert.strictEqual(path, 'args[0]');
assert.strictEqual(parent, d);
break;
case 3:
assert.strictEqual(node, c);
assert.strictEqual(path, 'args[1]');
assert.strictEqual(parent, d);
break;
}
});
assert.equal(count, 3);
});
it ('should clone a FunctionNode', function () {
// add(2, 3)
var s = new SymbolNode('add');
var b = new ConstantNode(2);
var c = new ConstantNode(3);
var d = new FunctionNode(s, [b, c]);
var e = d.clone();
assert(e instanceof FunctionNode);
assert.deepEqual(e, d);
assert.notStrictEqual(e, d);
assert.equal(e.name, d.name);
assert.notStrictEqual(e.args, d.args);
assert.strictEqual(e.args[0], d.args[0]);
assert.strictEqual(e.args[1], d.args[1]);
});
it ('test equality another Node', function () {
var a = new FunctionNode(new SymbolNode('add'), [new ConstantNode(2), new ConstantNode(3)]);
var b = new FunctionNode(new SymbolNode('add'), [new ConstantNode(2), new ConstantNode(3)]);
var c = new FunctionNode(new SymbolNode('subtract'), [new ConstantNode(2), new ConstantNode(3)]);
var d = new FunctionNode(new SymbolNode('add'), [new ConstantNode(4), new ConstantNode(3)]);
var e = new SymbolNode('add');
assert.strictEqual(a.equals(null), false);
assert.strictEqual(a.equals(undefined), false);
assert.strictEqual(a.equals(b), true);
assert.strictEqual(a.equals(c), false);
assert.strictEqual(a.equals(d), false);
assert.strictEqual(a.equals(e), false);
});
it ('should stringify a FunctionNode', function () {
var s = new SymbolNode('sqrt');
var c = new ConstantNode(4);
var n = new FunctionNode(s, [c]);
assert.equal(n.toString(), 'sqrt(4)');
});
it ('should pass options when stringifying a FunctionNode', function () {
var s = new SymbolNode('sqrt');
var a = new ConstantNode(2);
var b = new SymbolNode('x');
var c = new OperatorNode('*', 'multiply', [a, b], true); // implicit
var n = new FunctionNode(s, [c]);
assert.equal(n.toString(), 'sqrt(2 x)');
var options = {implicit: 'show'};
assert.equal(n.toString(options), 'sqrt(2 * x)');
});
it ('should stringify a FunctionNode with custom toString', function () {
//Also checks if the custom functions get passed on to the children
var customFunction = function (node, options) {
if (node.type === 'FunctionNode') {
var string = '[' + node.name + '](';
node.args.forEach(function (arg) {
string += arg.toString(options) + ', ';
});
string += ')';
return string;
}
else if (node.type === 'ConstantNode') {
return 'const(' + node.value + ', ' + node.valueType + ')'
}
};
var a = new ConstantNode(1);
var b = new ConstantNode(2);
var n1 = new FunctionNode(new SymbolNode('add'), [a, b]);
var n2 = new FunctionNode(new SymbolNode('subtract'), [a, b]);
assert.equal(n1.toString({handler: customFunction}), '[add](const(1, number), const(2, number), )');
assert.equal(n2.toString({handler: customFunction}), '[subtract](const(1, number), const(2, number), )');
});
it ('should stringify a FunctionNode with custom toString for a single function', function () {
//Also checks if the custom functions get passed on to the children
var customFunction = {
'add': function (node, options) {
return node.args[0].toString(options)
+ ' ' + node.name + ' '
+ node.args[1].toString(options);
}
};
var s = new SymbolNode('add');
var a = new ConstantNode(1);
var b = new ConstantNode(2);
var n = new FunctionNode(s, [a, b]);
assert.equal(n.toString({handler: customFunction}), '1 add 2');
});
it ('should LaTeX a FunctionNode', function () {
var s = new SymbolNode('sqrt');
var c1 = new ConstantNode(4);
var c2 = new ConstantNode(5);
var n = new FunctionNode(s, [c1]);
assert.equal(n.toTex(), '\\sqrt{4}');
// test permutations
var n2 = new FunctionNode(new SymbolNode('permutations'), [c1]);
assert.equal(n2.toTex(), '\\mathrm{permutations}\\left(4\\right)');
var o = new OperatorNode('+', 'add', [c1, c2]);
var n3 = new FunctionNode(new SymbolNode('permutations'), [o]);
assert.equal(n3.toTex(), '\\mathrm{permutations}\\left(4+5\\right)');
});
it ('should have an identifier', function () {
var s = new SymbolNode('factorial');
var a = new ConstantNode(2);
var n = new FunctionNode(s, [a]);
assert.equal(n.getIdentifier(), 'FunctionNode:factorial');
});
it ('should LaTeX a FunctionNode with custom toTex', function () {
//Also checks if the custom functions get passed on to the children
var customFunction = function (node, options) {
if (node.type === 'FunctionNode') {
var latex = '\\mbox{' + node.name + '}\\left(';
node.args.forEach(function (arg) {
latex += arg.toTex(options) + ', ';
});
latex += '\\right)';
return latex;
}
else if (node.type === 'ConstantNode') {
return 'const\\left(' + node.value + ', ' + node.valueType + '\\right)'
}
};
var a = new ConstantNode(1);
var b = new ConstantNode(2);
var n1 = new FunctionNode(new SymbolNode('add'), [a, b]);
var n2 = new FunctionNode(new SymbolNode('subtract'), [a, b]);
assert.equal(n1.toTex({handler: customFunction}), '\\mbox{add}\\left(const\\left(1, number\\right), const\\left(2, number\\right), \\right)');
assert.equal(n2.toTex({handler: customFunction}), '\\mbox{subtract}\\left(const\\left(1, number\\right), const\\left(2, number\\right), \\right)');
});
it ('should LaTeX a FunctionNode with custom toTex for a single function', function () {
//Also checks if the custom functions get passed on to the children
var customFunction = {
'add': function (node, options) {
return node.args[0].toTex(options)
+ ' ' + node.name + ' '
+ node.args[1].toTex(options);
}
};
var s = new SymbolNode('add');
var a = new ConstantNode(1);
var b = new ConstantNode(2);
var n = new FunctionNode(s, [a, b]);
assert.equal(n.toTex({handler: customFunction}), '1 add 2');
});
it ('should LaTeX a FunctionNode with callback attached to the function', function () {
var customMath = math.create();
customMath.add.toTex = function (node, options) {
return node.args[0].toTex(options) + ' plus ' + node.args[1].toTex(options);
};
assert.equal(customMath.parse('add(1,2)').toTex(), '1 plus 2');
});
it ('should LaTeX a FunctionNode with template string attached to the function', function () {
var customMath = math.create();
customMath.add.toTex = '${args[0]} plus ${args[1]}';
assert.equal(customMath.parse('add(1,2)').toTex(), '1 plus 2');
});
it ('should LaTeX a FunctionNode with object of callbacks attached to the function', function () {
var customMath = math.create();
customMath.sum.toTex = {
2: "${args[0]}+${args[1]}",
3: function (node, options) {
return node.args[0] + '+' + node.args[1] + '+' + node.args[2];
}
};
assert.equal(customMath.parse('sum(1,2)').toTex(), '1+2');
assert.equal(customMath.parse('sum(1,2,3)').toTex(), '1+2+3');
});
it ('should LaTeX templates with string properties', function () {
var customMath = math.create();
customMath.add.toTex = '${name}';
assert.equal(customMath.parse('add(1,2)').toTex(), 'add');
});
it ('should LaTeX templates with node properties', function () {
var customMath = math.create();
customMath.add.toTex = '${args[0]} plus ${args[1]}';
assert.equal(customMath.parse('add(1,2)').toTex(), '1 plus 2');
});
it ('should LaTeX templates with properties that are arrays of Nodes', function () {
var customMath = math.create();
customMath.add.toTex = '${args}';
assert.equal(customMath.parse('add(1,2)').toTex(), '1,2');
});
it ('should throw an Error for templates with properties that don\'t exist', function () {
var customMath = math.create();
customMath.add.toTex = '${some_property}';
assert.throws(function () {customMath.parse('add(1,2)').toTex()}, ReferenceError);
});
it ('should throw an Error for templates with properties that aren\'t Nodes or Strings or Arrays of Nodes', function () {
var customMath = math.create();
customMath.add.toTex = '${some_property}';
var tree = customMath.parse('add(1,2)');
tree.some_property = {};
assert.throws(function () {tree.toTex()}, TypeError);
customMath.add.prototype.some_property = 1;
tree.some_property = 1;
assert.throws(function () {tree.toTex()}, TypeError);
});
it ('should throw an Error for templates with properties that are arrays of non Nodes', function () {
var customMath = math.create();
customMath.add.toTex = '${some_property}';
var tree = customMath.parse('add(1,2)');
tree.some_property = [1,2];
assert.throws(function () {tree.toTex()}, TypeError);
});
});

View File

@@ -0,0 +1,254 @@
// test IndexNode
var assert = require('assert');
var approx = require('../../../tools/approx');
var math = require('../../../index');
var Node = math.expression.node.Node;
var ConstantNode = math.expression.node.ConstantNode;
var SymbolNode = math.expression.node.SymbolNode;
var IndexNode = math.expression.node.IndexNode;
var RangeNode = math.expression.node.RangeNode;
describe('IndexNode', function() {
it ('should create a IndexNode', function () {
var n = new IndexNode([]);
assert(n instanceof IndexNode);
assert(n instanceof Node);
assert.equal(n.type, 'IndexNode');
});
it ('should have isIndexNode', function () {
var node = new IndexNode([]);
assert(node.isIndexNode);
});
it ('should throw an error when calling with wrong arguments', function () {
assert.throws(function () {new IndexNode()}, TypeError);
assert.throws(function () {new IndexNode('a')}, TypeError);
assert.throws(function () {new IndexNode(new Node())}, TypeError);
assert.throws(function () {new IndexNode([new Node(), 3])}, TypeError);
});
it ('should throw an error when calling without new operator', function () {
assert.throws(function () {IndexNode([])}, SyntaxError);
});
it ('should filter an IndexNode', function () {
var b = new ConstantNode(2);
var c = new ConstantNode(1);
var n = new IndexNode([b, c]);
assert.deepEqual(n.filter(function (node) {return node instanceof IndexNode}), [n]);
assert.deepEqual(n.filter(function (node) {return node instanceof RangeNode}), []);
assert.deepEqual(n.filter(function (node) {return node instanceof ConstantNode}), [b, c]);
assert.deepEqual(n.filter(function (node) {return node instanceof ConstantNode && node.value == '2'}), [b]);
assert.deepEqual(n.filter(function (node) {return node instanceof ConstantNode && node.value == '4'}), []);
});
it ('should filter an empty IndexNode', function () {
var n = new IndexNode([]);
assert.deepEqual(n.filter(function (node) {return node instanceof IndexNode}), [n]);
assert.deepEqual(n.filter(function (node) {return node instanceof ConstantNode}), []);
});
it ('should run forEach on an IndexNode', function () {
var b = new ConstantNode(2);
var c = new ConstantNode(1);
var n = new IndexNode([b, c]);
var nodes = [];
var paths = [];
n.forEach(function (node, path, parent) {
nodes.push(node);
paths.push(path);
assert.strictEqual(parent, n);
});
assert.equal(nodes.length, 2);
assert.strictEqual(nodes[0], b);
assert.strictEqual(nodes[1], c);
assert.deepEqual(paths, ['dimensions[0]', 'dimensions[1]']);
});
it ('should map an IndexNode', function () {
var b = new ConstantNode(2);
var c = new ConstantNode(1);
var n = new IndexNode([b, c]);
var nodes = [];
var paths = [];
var e = new ConstantNode(-1);
var f = n.map(function (node, path, parent) {
nodes.push(node);
paths.push(path);
assert.strictEqual(parent, n);
return node.isConstantNode && node.value === '1' ? e : node;
});
assert.equal(nodes.length, 2);
assert.strictEqual(nodes[0], b);
assert.strictEqual(nodes[1], c);
assert.deepEqual(paths, ['dimensions[0]', 'dimensions[1]']);
assert.notStrictEqual(f, n);
assert.deepEqual(f.dimensions[0], b);
assert.deepEqual(f.dimensions[1], e);
});
it ('should throw an error when the map callback does not return a node', function () {
var b = new ConstantNode(2);
var c = new ConstantNode(1);
var n = new IndexNode([b, c]);
assert.throws(function () {
n.map(function () {});
}, /Callback function must return a Node/)
});
it ('should transform an IndexNodes (nested) parameters', function () {
var b = new ConstantNode(2);
var c = new ConstantNode(1);
var n = new IndexNode([b, c]);
var e = new SymbolNode('c');
var f = n.transform(function (node) {
return node.isConstantNode && node.value === '1' ? e : node;
});
assert.notStrictEqual(f, n);
assert.deepEqual(f.dimensions[0], b);
assert.deepEqual(f.dimensions[1], e);
});
it ('should transform an IndexNode itself', function () {
var b = new ConstantNode(2);
var c = new ConstantNode(1);
var n = new IndexNode([b, c]);
var e = new ConstantNode(5);
var f = n.transform(function (node) {
return node.isIndexNode ? e : node;
});
assert.notStrictEqual(f, n);
assert.deepEqual(f, e);
});
it ('should clone an IndexNode', function () {
var b = new ConstantNode(2);
var c = new ConstantNode(1);
var n = new IndexNode([b, c]);
var d = n.clone();
assert(d.isIndexNode);
assert.deepEqual(d, n);
assert.notStrictEqual(d, n);
assert.notStrictEqual(d.dimensions, n.dimensions);
assert.strictEqual(d.dimensions[0], n.dimensions[0]);
assert.strictEqual(d.dimensions[1], n.dimensions[1]);
});
it ('test equality another Node', function () {
var a = new IndexNode([new ConstantNode(2), new ConstantNode(1)]);
var b = new IndexNode([new ConstantNode(2), new ConstantNode(1)]);
var c = new IndexNode([new ConstantNode(2)]);
var d = new IndexNode([new ConstantNode(2), new ConstantNode(1), new ConstantNode(3)]);
var e = new IndexNode([new ConstantNode(2), new ConstantNode(4)]);
var f = new SymbolNode('x');
assert.strictEqual(a.equals(null), false);
assert.strictEqual(a.equals(undefined), false);
assert.strictEqual(a.equals(b), true);
assert.strictEqual(a.equals(c), false);
assert.strictEqual(a.equals(d), false);
assert.strictEqual(a.equals(e), false);
assert.strictEqual(a.equals(f), false);
});
it ('should stringify an IndexNode', function () {
var dimensions = [
new ConstantNode(2),
new ConstantNode(1)
];
var n = new IndexNode(dimensions);
assert.equal(n.toString(), '[2, 1]');
var n2 = new IndexNode([]);
assert.equal(n2.toString(), '[]')
});
it ('should stringify an IndexNode with dot notation', function () {
var dimensions = [new ConstantNode('a')];
var n = new IndexNode(dimensions, true);
assert.equal(n.toString(), '.a');
});
it ('should stringigy an IndexNode with custom toString', function () {
//Also checks if the custom functions get passed on to the children
var customFunction = function (node, options) {
if (node.type === 'IndexNode') {
return node.dimensions.map(function (range) {
return range.toString(options);
}).join(', ');
}
else if (node.type === 'ConstantNode') {
return 'const(' + node.value + ', ' + node.valueType + ')'
}
};
var b = new ConstantNode(1);
var c = new ConstantNode(2);
var n = new IndexNode([b, c]);
assert.equal(n.toString({handler: customFunction}), 'const(1, number), const(2, number)');
});
it ('should LaTeX an IndexNode', function () {
var dimensions = [
new ConstantNode(2),
new ConstantNode(1)
];
var n = new IndexNode(dimensions);
assert.equal(n.toTex(), '_{2,1}');
var n2 = new IndexNode([]);
assert.equal(n2.toTex(), '_{}')
});
it ('should LaTeX an IndexNode with dot notation', function () {
var dimensions = [new ConstantNode('a')];
var n = new IndexNode(dimensions, true);
assert.equal(n.toString(), '.a');
});
it ('should LaTeX an IndexNode with custom toTex', function () {
//Also checks if the custom functions get passed on to the children
var customFunction = function (node, options) {
if (node.type === 'IndexNode') {
return node.dimensions.map(function (range) {
return range.toTex(options);
}).join(', ');
return latex;
}
else if (node.type === 'ConstantNode') {
return 'const\\left(' + node.value + ', ' + node.valueType + '\\right)'
}
};
var b = new ConstantNode(1);
var c = new ConstantNode(2);
var n = new IndexNode([b, c]);
assert.equal(n.toTex({handler: customFunction}), 'const\\left(1, number\\right), const\\left(2, number\\right)');
});
});

View File

@@ -0,0 +1,174 @@
// test Node
var assert = require('assert');
var approx = require('../../../tools/approx');
var math = require('../../../index');
var Node = math.expression.node.Node;
describe('Node', function() {
function MyNode (value) {
this.value = value;
}
MyNode.prototype = new Node();
MyNode.prototype.forEach = function () {};
MyNode.prototype.map = function () {
return new MyNode(this.value);
};
it ('should create a Node', function () {
var n = new Node();
assert(n instanceof Node);
});
it ('should have isNode', function () {
var node = new Node();
assert(node.isNode);
});
it ('should throw an error when calling without new operator', function () {
assert.throws(function () {Node()}, SyntaxError);
});
it ('should filter a Node', function () {
var n = new MyNode(2);
assert.deepEqual(n.filter(function () {return true}), [n]);
assert.deepEqual(n.filter(function (node) {return node instanceof Node}), [n]);
assert.deepEqual(n.filter(function (node) {return node instanceof Date}), []);
});
it ('should transform a Node', function () {
var a = new MyNode(2);
var b = new MyNode(3);
var c = a.transform(function (node) {
return b;
});
assert.deepEqual(c, b);
// no match
a = new MyNode(2);
b = new MyNode(3);
c = a.transform(function (node) {
return node;
});
assert.deepEqual(c, a);
});
it ('should transform a Node using a replacement function', function () {
var a = new MyNode(2);
var b = new MyNode(3);
var c = a.transform(function (node) {
assert.deepEqual(node, a);
return b;
});
assert.deepEqual(c, b);
});
it ('should throw an error when cloning a Node interface', function () {
assert.throws(function () {
var a = new Node();
a.clone();
}, /Cannot clone a Node interface/);
});
it ('should shallow clone the content of a Node', function () {
var a = new math.expression.node.ConstantNode(1);
var b = new math.expression.node.ConstantNode(2);
var c = new math.expression.node.OperatorNode('+', 'add', [a, b]);
var clone = c.clone();
assert.deepEqual(c, clone);
assert.notStrictEqual(c, clone);
assert.strictEqual(clone.args[0], c.args[0]);
assert.strictEqual(clone.args[1], c.args[1]);
});
it ('should deepClone the content of a Node', function () {
var a = new math.expression.node.ConstantNode(1);
var b = new math.expression.node.ConstantNode(2);
var c = new math.expression.node.OperatorNode('+', 'add', [a, b]);
var clone = c.cloneDeep();
assert.deepEqual(c, clone);
assert.notStrictEqual(c, clone);
assert.notStrictEqual(clone.args[0], c.args[0]);
assert.notStrictEqual(clone.args[1], c.args[1]);
});
it ('test equality with another Node', function () {
assert.strictEqual(new Node().equals(new Node()), true);
assert.strictEqual(new Node().equals(null), false);
assert.strictEqual(new Node().equals(undefined), false);
assert.strictEqual(new Node().equals({}), false);
});
it ('should throw an error when stringifying a Node interface', function () {
assert.throws(function () {
var node = new Node();
node.toString();
}, /_toString not implemented for Node/);
});
it ('should throw an error when calling _toTex', function () {
assert.throws(function () {
var node = new Node();
node._toTex();
}, /_toTex not implemented for Node/);
});
it ('should ignore custom toString if it returns nothing', function () {
var callback1 = function (node, callback) {};
var callback2 = {
bla: function (node, callbacks) {}
};
var mymath = math.create();
mymath.expression.node.Node.prototype._toString = function () {
return 'default';
};
var n1 = new mymath.expression.node.Node();
var s = new mymath.expression.node.SymbolNode('bla');
var n2 = new mymath.expression.node.FunctionNode(s, []);
assert.equal(n1.toString(callback1), 'default');
assert.equal(n2.toString(callback2), 'bla()');
});
it ('should ignore custom toTex if it returns nothing', function () {
var callback1 = function (node, callback) {};
var callback2 = {
bla: function (node, callbacks) {}
};
var mymath = math.create();
mymath.expression.node.Node.prototype._toTex = function () {
return 'default';
};
var n1 = new mymath.expression.node.Node();
var s = new mymath.expression.node.SymbolNode('bla');
var n2 = new mymath.expression.node.FunctionNode(s, []);
assert.equal(n1.toTex(callback1), 'default');
assert.equal(n2.toTex(callback2), '\\mathrm{bla}\\left(\\right)');
});
it ('should throw an error when compiling an abstract node', function () {
var node = new Node();
assert.throws(function () {
node.compile()
}, /Cannot compile a Node interface/);
});
it ('should have an identifier', function () {
var node = new Node();
assert.equal(node.getIdentifier(), 'Node');
});
it ('should get the content of a Node', function () {
var c = new math.expression.node.ConstantNode(1);
assert.equal(c.getContent(), c);
assert.deepEqual(c.getContent(), c);
});
});

View File

@@ -0,0 +1,285 @@
// test ObjectNode
var assert = require('assert');
var approx = require('../../../tools/approx');
var math = require('../../../index');
var Node = math.expression.node.Node;
var ConstantNode = math.expression.node.ConstantNode;
var SymbolNode = math.expression.node.SymbolNode;
var RangeNode = math.expression.node.RangeNode;
var ObjectNode = math.expression.node.ObjectNode;
// FIXME: a lot of tests depend on order of object keys, whilst the order is officially undeterministic
describe('ObjectNode', function() {
it ('should create an ObjectNode', function () {
var c = new ConstantNode(1);
var a = new ObjectNode({c: c});
var b = new ObjectNode();
assert(a instanceof ObjectNode);
assert(b instanceof ObjectNode);
assert.equal(a.type, 'ObjectNode');
assert.equal(b.type, 'ObjectNode');
});
it ('should have isObjectNode', function () {
var node = new ObjectNode({});
assert(node.isObjectNode);
});
it ('should throw an error when calling without new operator', function () {
assert.throws(function () {ObjectNode()}, SyntaxError);
});
it ('should throw an error on wrong constructor arguments', function () {
assert.throws(function () {new ObjectNode(2)}, TypeError);
assert.throws(function () {new ObjectNode({a: 2, b: 3})}, TypeError);
});
it ('should evaluate an ObjectNode', function () {
var c = new ConstantNode(1);
var a = new ObjectNode({c: c});
var b = new ObjectNode();
assert.deepEqual(a.compile().eval(), {c: 1});
assert.deepEqual(b.compile().eval(), {});
});
it ('should compile nested ObjectNodes', function () {
var a = new ConstantNode(1);
var b = new ConstantNode(2);
var c = new ConstantNode(3);
var d = new ConstantNode(4);
var n2 = new ObjectNode({a: a, b: b});
var n3 = new ObjectNode({c: c, d: d});
var n4 = new ObjectNode({n2: n2, n3: n3});
var expr = n4.compile();
assert.deepEqual(expr.eval(), {n2: {a: 1, b: 2}, n3: {c: 3, d: 4}});
});
it ('should filter an ObjectNode', function () {
var a = new ConstantNode(1);
var b = new SymbolNode('x');
var c = new ConstantNode(2);
var d = new ObjectNode({a: a, b: b, c: c});
assert.deepEqual(d.filter(function (node) {return node instanceof ObjectNode}), [d]);
assert.deepEqual(d.filter(function (node) {return node instanceof SymbolNode}), [b]);
assert.deepEqual(d.filter(function (node) {return node instanceof RangeNode}), []);
assert.deepEqual(d.filter(function (node) {return node instanceof ConstantNode}), [a, c]);
assert.deepEqual(d.filter(function (node) {return node instanceof ConstantNode && node.value == '2'}), [c]);
});
it ('should run forEach on an ObjectNode', function () {
var a = new SymbolNode('x');
var b = new ConstantNode(2);
var c = new ObjectNode({a: a, b: b});
var nodes = [];
var paths = [];
c.forEach(function (node, path, parent) {
nodes.push(node);
paths.push(path);
assert.strictEqual(parent, c);
});
assert.deepEqual(paths, ['properties["a"]', 'properties["b"]']);
assert.equal(nodes.length, 2);
assert.strictEqual(nodes[0], a);
assert.strictEqual(nodes[1], b);
});
it ('should map an ObjectNode', function () {
var a = new SymbolNode('x');
var b = new ConstantNode(2);
var c = new ObjectNode({a: a, b: b});
var d = new ConstantNode(3);
var nodes = [];
var paths = [];
var e = c.map(function (node, path, parent) {
nodes.push(node);
paths.push(path);
assert.strictEqual(parent, c);
return (node instanceof SymbolNode) && (node.name == 'x') ? d : node;
});
assert.deepEqual(paths, ['properties["a"]', 'properties["b"]']);
assert.equal(nodes.length, 2);
assert.strictEqual(nodes[0], a);
assert.strictEqual(nodes[1], b);
assert.notStrictEqual(e, c);
assert.deepEqual(e.properties["a"], d);
assert.deepEqual(e.properties["b"], b);
});
it ('should throw an error when the map callback does not return a node', function () {
var a = new SymbolNode('x');
var b = new ConstantNode(2);
var c = new ObjectNode({a: a, b: b});
assert.throws(function () {
c.map(function () {});
}, /Callback function must return a Node/)
});
it ('should transform an ObjectNodes parameters', function () {
var a = new SymbolNode('x');
var b = new ConstantNode(2);
var c = new ObjectNode({a: a, b: b});
var d = new ConstantNode(3);
var e = c.transform(function (node) {
return (node instanceof SymbolNode) && (node.name == 'x') ? d : node;
});
assert.notStrictEqual(e, c);
assert.deepEqual(e.properties["a"], d);
assert.deepEqual(e.properties["b"], b);
});
it ('should transform an ObjectNode itself', function () {
var a = new SymbolNode('x');
var b = new ConstantNode(2);
var c = new ObjectNode({a: a, b: b});
var d = new ConstantNode(3);
var e = c.transform(function (node) {
return (node instanceof ObjectNode) ? d : node;
});
assert.notStrictEqual(e, c);
assert.deepEqual(e, d);
});
it ('should traverse an ObjectNode', function () {
var a = new ConstantNode(1);
var b = new ConstantNode(2);
var c = new ConstantNode(3);
var d = new ObjectNode({a: a, b: b});
var e = new ObjectNode({c: c, d: d});
var count = 0;
e.traverse(function (node, path, parent) {
count++;
switch(count) {
case 1:
assert.strictEqual(path, null);
assert.strictEqual(node, e);
assert.strictEqual(parent, null);
break;
case 2:
assert.strictEqual(path, 'properties["c"]');
assert.strictEqual(node, c);
assert.strictEqual(parent, e);
break;
case 3:
assert.strictEqual(path, 'properties["d"]');
assert.strictEqual(node, d);
assert.strictEqual(parent, e);
break;
case 4:
assert.strictEqual(path, 'properties["a"]');
assert.strictEqual(node, a);
assert.strictEqual(parent, d);
break;
case 5:
assert.strictEqual(path, 'properties["b"]');
assert.strictEqual(node, b);
assert.strictEqual(parent, d);
break;
}
});
assert.equal(count, 5);
});
it ('should clone an ObjectNode', function () {
var a = new SymbolNode('x');
var b = new ConstantNode(2);
var c = new ObjectNode({a: a, b: b});
var d = c.clone();
assert(d instanceof ObjectNode);
assert.deepEqual(c, d);
assert.notStrictEqual(c, d);
assert.strictEqual(c.properties["a"], d.properties["a"]);
assert.strictEqual(c.properties["b"], d.properties["b"]);
});
it ('test equality another Node', function () {
var a = new ObjectNode({a: new SymbolNode('a'), b: new ConstantNode(2)});
var b = new ObjectNode({a: new SymbolNode('a'), b: new ConstantNode(2)});
var c = new ObjectNode({a: new SymbolNode('a'), b: new ConstantNode(2), c: new ConstantNode(3)});
var d = new ObjectNode({a: new SymbolNode('foo'), b: new ConstantNode(2)});
var e = new ObjectNode({a: new SymbolNode('a')});
var f = new SymbolNode('x');
assert.strictEqual(a.equals(null), false);
assert.strictEqual(a.equals(undefined), false);
assert.strictEqual(a.equals(b), true);
assert.strictEqual(a.equals(c), false);
assert.strictEqual(a.equals(d), false);
assert.strictEqual(a.equals(e), false);
assert.strictEqual(a.equals(f), false);
});
it ('should stringify an ObjectNode', function () {
var a = new ConstantNode(1);
var b = new ConstantNode(2);
var c = new ConstantNode(3);
var n1 = new ObjectNode({a: a, b: b});
var n2 = new ObjectNode({c: c, n1: n1});
assert.equal(n2.toString(), '{"c": 3, "n1": {"a": 1, "b": 2}}');
});
it ('should stringify an ObjectNode with custom toString', function () {
var customFunction = function (node, options) {
if (node.type === 'ConstantNode') {
return 'const(' + node.value + ', ' + node.valueType + ')'
}
};
var a = new ConstantNode(1);
var b = new ConstantNode(2);
var n = new ObjectNode({a: a, b: b});
assert.equal(n.toString({handler: customFunction}), '{"a": const(1, number), "b": const(2, number)}');
});
it ('should LaTeX an ObjectNode', function () {
var a = new ConstantNode(1);
var b = new ConstantNode(2);
var c = new ConstantNode(3);
var n1 = new ObjectNode({a: a, b: b});
var n2 = new ObjectNode({c: c, n1: n1});
assert.equal(n2.toTex(), '\\left\\{\\begin{array}{ll}\\mathbf{c:} & 3\\\\\n\\mathbf{n1:} & \\left\\{\\begin{array}{ll}\\mathbf{a:} & 1\\\\\n\\mathbf{b:} & 2\\\\\\end{array}\\right\\}\\\\\\end{array}\\right\\}')
});
it ('should LaTeX an ObjectNode with custom toTex', function () {
var customFunction = function (node, options) {
if (node.type === 'ConstantNode') {
return 'const\\left(' + node.value + ', ' + node.valueType + '\\right)'
}
};
var a = new ConstantNode(1);
var b = new ConstantNode(2);
var n = new ObjectNode({a: a, b: b});
assert.equal(n.toTex({handler: customFunction}), '\\left\\{\\begin{array}{ll}\\mathbf{a:} & const\\left(1, number\\right)\\\\\n\\mathbf{b:} & const\\left(2, number\\right)\\\\\\end{array}\\right\\}');
});
});

View File

@@ -0,0 +1,727 @@
// test OperatorNode
var assert = require('assert');
var approx = require('../../../tools/approx');
var math = require('../../../index');
var Node = math.expression.node.Node;
var ConstantNode = math.expression.node.ConstantNode;
var SymbolNode = math.expression.node.SymbolNode;
var OperatorNode = math.expression.node.OperatorNode;
var ConditionalNode = math.expression.node.ConditionalNode;
describe('OperatorNode', function() {
it ('should create an OperatorNode', function () {
var n = new OperatorNode('op', 'fn', []);
assert(n instanceof OperatorNode);
assert(n instanceof Node);
assert.equal(n.type, 'OperatorNode');
});
it ('should have isOperatorNode', function () {
var node = new OperatorNode('op', 'fn', []);
assert(node.isOperatorNode);
});
it ('should throw an error when calling without new operator', function () {
var a = new ConstantNode(2);
var b = new ConstantNode(3);
assert.throws(function () {OperatorNode('+', 'add', [a, b])}, SyntaxError);
});
it ('should compile an OperatorNode', function () {
var a = new ConstantNode(2);
var b = new ConstantNode(3);
var n = new OperatorNode('+', 'add', [a, b]);
var expr = n.compile();
assert.equal(expr.eval(), 5);
});
it ('should throw an error in case of unresolved operator function', function () {
var a = new ConstantNode(2);
var b = new ConstantNode(3);
var n = new OperatorNode('***', 'foo', [a, b]);
assert.throws(function () {
n.compile();
}, /Function foo missing in provided namespace/);
});
it ('should filter an OperatorNode', function () {
var a = new ConstantNode(2);
var b = new ConstantNode(3);
var n = new OperatorNode('+', 'add', [a, b]);
assert.deepEqual(n.filter(function (node) {return node instanceof OperatorNode}), [n]);
assert.deepEqual(n.filter(function (node) {return node instanceof SymbolNode}), []);
assert.deepEqual(n.filter(function (node) {return node instanceof ConstantNode}), [a, b]);
assert.deepEqual(n.filter(function (node) {return node instanceof ConstantNode && node.value == '2'}), [a]);
assert.deepEqual(n.filter(function (node) {return node instanceof ConstantNode && node.value == '4'}), []);
});
it ('should filter an OperatorNode without contents', function () {
var n = new OperatorNode('op', 'fn', []);
assert.deepEqual(n.filter(function (node) {return node instanceof OperatorNode}), [n]);
assert.deepEqual(n.filter(function (node) {return node instanceof SymbolNode}), []);
});
it ('should run forEach on an OperatorNode', function () {
// x^2-x
var a = new SymbolNode('x');
var b = new ConstantNode(2);
var c = new OperatorNode('^', 'pow', [a, b]);
var d = new SymbolNode('x');
var e = new OperatorNode('-', 'subtract', [c, d]);
var nodes = [];
var paths = [];
e.forEach(function (node, path, parent) {
nodes.push(node);
paths.push(path);
assert.strictEqual(parent, e);
});
assert.equal(nodes.length, 2);
assert.strictEqual(nodes[0], c);
assert.strictEqual(nodes[1], d);
assert.deepEqual(paths, ['args[0]', 'args[1]']);
});
it ('should map an OperatorNode', function () {
// x^2-x
var a = new SymbolNode('x');
var b = new ConstantNode(2);
var c = new OperatorNode('^', 'pow', [a, b]);
var d = new SymbolNode('x');
var e = new OperatorNode('-', 'subtract', [c, d]);
var nodes = [];
var paths = [];
var f = new ConstantNode(3);
var g = e.map(function (node, path, parent) {
nodes.push(node);
paths.push(path);
assert.strictEqual(parent, e);
return node instanceof SymbolNode && node.name == 'x' ? f : node;
});
assert.equal(nodes.length, 2);
assert.strictEqual(nodes[0], c);
assert.strictEqual(nodes[1], d);
assert.deepEqual(paths, ['args[0]', 'args[1]']);
assert.notStrictEqual(g, e);
assert.strictEqual(g.args[0], e.args[0]);
assert.strictEqual(g.args[0].args[0], a); // nested x is not replaced
assert.deepEqual(g.args[0].args[1], b);
assert.deepEqual(g.args[1], f);
});
it ('should throw an error when the map callback does not return a node', function () {
var a = new SymbolNode('x');
var b = new ConstantNode(2);
var c = new OperatorNode('^', 'pow', [a, b]);
assert.throws(function () {
c.map(function () {});
}, /Callback function must return a Node/)
});
it ('should transform an OperatorNodes parameters', function () {
// x^2-x
var a = new SymbolNode('x');
var b = new ConstantNode(2);
var c = new OperatorNode('^', 'pow', [a, b]);
var d = new SymbolNode('x');
var e = new OperatorNode('-', 'subtract', [c, d]);
var f = new ConstantNode(3);
var g = e.transform(function (node) {
return node instanceof SymbolNode && node.name == 'x' ? f : node;
});
assert.deepEqual(g.args[1], f);
});
it ('should transform an OperatorNode itself', function () {
// x^2-x
var a = new SymbolNode('x');
var b = new ConstantNode(2);
var c = new OperatorNode('+', 'add', [a, b]);
var f = new ConstantNode(3);
var g = c.transform(function (node) {
return node instanceof OperatorNode ? f : node;
});
assert.notStrictEqual(g, c);
assert.deepEqual(g, f);
});
it ('should clone an OperatorNode', function () {
// x^2-x
var a = new SymbolNode('x');
var b = new ConstantNode(2);
var c = new OperatorNode('+', 'add', [a, b]);
var d = c.clone();
assert(d instanceof OperatorNode);
assert.deepEqual(d, c);
assert.notStrictEqual(d, c);
assert.notStrictEqual(d.args, c.args);
assert.strictEqual(d.args[0], c.args[0]);
assert.strictEqual(d.args[1], c.args[1]);
});
it ('should clone implicit multiplications', function () {
var two = new ConstantNode(2);
var x = new SymbolNode('x');
var node = new OperatorNode('*', 'multiply', [two, x], true);
assert.equal('2 x', node.toString());
assert.strictEqual(true, node.clone().implicit);
assert.equal(node.toString(), node.clone().toString());
});
it ('test equality another Node', function () {
var a = new OperatorNode('+', 'add', [new SymbolNode('x'), new ConstantNode(2)]);
var b = new OperatorNode('+', 'add', [new SymbolNode('x'), new ConstantNode(2)]);
var c = new OperatorNode('*', 'multiply', [new SymbolNode('x'), new ConstantNode(2)]);
var d = new OperatorNode('*', 'add', [new SymbolNode('x'), new ConstantNode(3)]);
var e = new OperatorNode('*', 'add', [new SymbolNode('x'), new ConstantNode(2), new ConstantNode(4)]);
assert.strictEqual(a.equals(null), false);
assert.strictEqual(a.equals(undefined), false);
assert.strictEqual(a.equals(b), true);
assert.strictEqual(a.equals(c), false);
assert.strictEqual(a.equals(d), false);
assert.strictEqual(a.equals(e), false);
});
describe('toString', function () {
it ('should stringify an OperatorNode', function () {
var a = new ConstantNode(2);
var b = new ConstantNode(3);
var c = new ConstantNode(4);
var n = new OperatorNode('+', 'add', [a, b]);
assert.equal(n.toString(), '2 + 3');
});
it ('should stringify an OperatorNode with factorial', function () {
var a = new ConstantNode(2);
var n = new OperatorNode('!', 'factorial', [a]);
assert.equal(n.toString(), '2!');
});
it ('should stringify an OperatorNode with unary minus', function () {
var a = new ConstantNode(2);
var n = new OperatorNode('-', 'unaryMinus', [a]);
assert.equal(n.toString(), '-2');
});
it ('should stringify an OperatorNode with zero arguments', function () {
var n = new OperatorNode('foo', 'foo', []);
assert.equal(n.toString(), 'foo()');
});
it ('should stringify an OperatorNode with more than two operators', function () {
var a = new ConstantNode(2);
var b = new ConstantNode(3);
var c = new ConstantNode(4);
var n = new OperatorNode('foo', 'foo', [a, b, c]);
assert.equal(n.toString(), 'foo(2, 3, 4)');
});
it ('should stringify addition and multiplication with more than two operands', function () {
var a = new SymbolNode('a');
var b = new SymbolNode('b');
var c = new SymbolNode('c');
var add = new OperatorNode('+', 'add', [a, b, c]);
var multiply = new OperatorNode('*', 'multiply', [a, b, c]);
var implicitMultiply = new OperatorNode('*', 'multiply', [a, b, c], true);
assert.equal(add.toString(), 'a + b + c');
assert.equal(multiply.toString(), 'a * b * c');
assert.equal(implicitMultiply.toString(), 'a b c');
});
it ('should stringify addition and multiplication with more than two operands including OperatorNode', function () {
var a = new SymbolNode('a');
var b = new SymbolNode('b');
var c = new SymbolNode('c');
var d = new SymbolNode('d');
var mult = new OperatorNode('*', 'multiply', [a,b]);
var add = new OperatorNode('+', 'add', [a, b]);
var multipleMultWithMult = new OperatorNode('*', 'multiply', [c, mult, d]);
var multipleMultWithAdd = new OperatorNode('*', 'multiply', [c, add, d]);
var multipleAddWithMult = new OperatorNode('+', 'add', [c, mult, d]);
var multipleAddWithAdd = new OperatorNode('+', 'add', [c, add, d]);
assert.equal(multipleMultWithMult.toString(), 'c * a * b * d');
assert.equal(multipleMultWithAdd.toString(), 'c * (a + b) * d');
assert.equal(multipleAddWithMult.toString(), 'c + a * b + d');
assert.equal(multipleAddWithAdd.toString(), 'c + a + b + d');
});
it ('should stringify an OperatorNode that contains an operatornode with more than two operands', function () {
var a = new SymbolNode('a');
var b = new SymbolNode('b');
var c = new SymbolNode('c');
var d = new SymbolNode('d');
var mult = new OperatorNode('*', 'multiply', [a, b, c]);
var add = new OperatorNode('+', 'add', [a, b, c]);
var addWithMult = new OperatorNode('+', 'add', [mult, d]);
var addWithAdd = new OperatorNode('+', 'add', [add, d]);
var multWithMult = new OperatorNode('*', 'multiply', [mult, d]);
var multWithAdd = new OperatorNode('*', 'multiply', [add, d]);
assert.equal(addWithMult.toString(), 'a * b * c + d');
assert.equal(addWithAdd.toString(), 'a + b + c + d');
assert.equal(multWithMult.toString(), 'a * b * c * d');
assert.equal(multWithAdd.toString(), '(a + b + c) * d');
});
it ('should stringify an OperatorNode with nested operator nodes', function () {
var a = new ConstantNode(2);
var b = new ConstantNode(3);
var c = new ConstantNode(4);
var d = new ConstantNode(5);
var n1 = new OperatorNode('+', 'add', [a, b]);
var n2 = new OperatorNode('-', 'subtract', [c, d]);
var n3 = new OperatorNode('*', 'multiply', [n1, n2]);
assert.equal(n1.toString(), '2 + 3');
assert.equal(n2.toString(), '4 - 5');
assert.equal(n3.toString(), '(2 + 3) * (4 - 5)');
});
it ('should stringify left associative OperatorNodes that are associative with another Node', function () {
assert.equal(math.parse('(a+b)+c').toString({parenthesis: 'auto'}), 'a + b + c');
assert.equal(math.parse('a+(b+c)').toString({parenthesis: 'auto'}), 'a + b + c');
assert.equal(math.parse('(a+b)-c').toString({parenthesis: 'auto'}), 'a + b - c');
assert.equal(math.parse('a+(b-c)').toString({parenthesis: 'auto'}), 'a + b - c');
assert.equal(math.parse('(a*b)*c').toString({parenthesis: 'auto'}), 'a * b * c');
assert.equal(math.parse('a*(b*c)').toString({parenthesis: 'auto'}), 'a * b * c');
assert.equal(math.parse('(a*b)/c').toString({parenthesis: 'auto'}), 'a * b / c');
assert.equal(math.parse('a*(b/c)').toString({parenthesis: 'auto'}), 'a * b / c');
});
it ('should stringify left associative OperatorNodes that are not associative with another Node', function () {
assert.equal(math.parse('(a-b)-c').toString({parenthesis: 'auto'}), 'a - b - c');
assert.equal(math.parse('a-(b-c)').toString({parenthesis: 'auto'}), 'a - (b - c)');
assert.equal(math.parse('(a-b)+c').toString({parenthesis: 'auto'}), 'a - b + c');
assert.equal(math.parse('a-(b+c)').toString({parenthesis: 'auto'}), 'a - (b + c)');
assert.equal(math.parse('(a/b)/c').toString({parenthesis: 'auto'}), 'a / b / c');
assert.equal(math.parse('a/(b/c)').toString({parenthesis: 'auto'}), 'a / (b / c)');
assert.equal(math.parse('(a/b)*c').toString({parenthesis: 'auto'}), 'a / b * c');
assert.equal(math.parse('a/(b*c)').toString({parenthesis: 'auto'}), 'a / (b * c)');
});
it ('should stringify right associative OperatorNodes that are not associative with another Node', function () {
assert.equal(math.parse('(a^b)^c').toString({parenthesis: 'auto'}), '(a ^ b) ^ c');
assert.equal(math.parse('a^(b^c)').toString({parenthesis: 'auto'}), 'a ^ b ^ c');
});
it ('should stringify unary OperatorNodes containing a binary OperatorNode', function () {
assert.equal(math.parse('(a*b)!').toString(), '(a * b)!');
assert.equal(math.parse('-(a*b)').toString(), '-(a * b)');
assert.equal(math.parse('-(a+b)').toString(), '-(a + b)');
});
it ('should stringify unary OperatorNodes containing a unary OperatorNode', function () {
assert.equal(math.parse('(-a)!').toString({parenthesis: 'auto'}), '(-a)!');
assert.equal(math.parse('-(a!)').toString({parenthesis: 'auto'}), '-a!');
assert.equal(math.parse('-(-a)').toString({parenthesis: 'auto'}), '-(-a)');
});
});
it ('should stringify an OperatorNode with custom toString', function () {
//Also checks if the custom functions get passed on to the children
var customFunction = function (node, options) {
if (node.type === 'OperatorNode') {
return node.op + node.fn + '('
+ node.args[0].toString(options)
+ ', ' + node.args[1].toString(options) + ')';
}
else if (node.type === 'ConstantNode') {
return 'const(' + node.value + ', ' + node.valueType + ')'
}
};
var a = new ConstantNode(1);
var b = new ConstantNode(2);
var n1 = new OperatorNode('+', 'add', [a, b]);
var n2 = new OperatorNode('-', 'subtract', [a, b]);
assert.equal(n1.toString({handler: customFunction}), '+add(const(1, number), const(2, number))');
assert.equal(n2.toString({handler: customFunction}), '-subtract(const(1, number), const(2, number))');
});
it ('should stringify an OperatorNode with custom toString for a single operator', function () {
//Also checks if the custom functions get passed on to the children
var customFunction = function (node, options) {
if ((node.type === 'OperatorNode') && (node.fn === 'add')) {
return node.args[0].toString(options)
+ node.op + node.fn + node.op +
node.args[1].toString(options);
}
else if (node.type === 'ConstantNode') {
return 'const(' + node.value + ', ' + node.valueType + ')'
}
};
var a = new ConstantNode(1);
var b = new ConstantNode(2);
var n = new OperatorNode('+', 'add', [a, b]);
assert.equal(n.toString({handler: customFunction}), 'const(1, number)+add+const(2, number)');
});
it ('should respect the \'all\' parenthesis option', function () {
assert.equal(math.parse('1+1+1').toString({parenthesis: 'all'}), '(1 + 1) + 1' );
assert.equal(math.parse('1+1+1').toTex({parenthesis: 'all'}), '\\left(1+1\\right)+1' );
});
it ('should correctly LaTeX fractions in \'all\' parenthesis mode', function () {
assert.equal(math.parse('1/2/3').toTex({parenthesis: 'all'}), '\\frac{\\left(\\frac{1}{2}\\right)}{3}');
});
it ('should LaTeX an OperatorNode', function () {
var a = new ConstantNode(2);
var b = new ConstantNode(3);
var c = new ConstantNode(4);
var n = new OperatorNode('+', 'add', [a, b]);
assert.equal(n.toTex(), '2+3');
});
it ('should LaTeX an OperatorNode with factorial', function () {
var a = new ConstantNode(2);
var n = new OperatorNode('!', 'factorial', [a]);
assert.equal(n.toTex(), '2!');
});
it ('should LaTeX an OperatorNode with factorial of an OperatorNode', function () {
var a = new ConstantNode(2);
var b = new ConstantNode(3);
var sub = new OperatorNode('-', 'subtract', [a, b]);
var add = new OperatorNode('+', 'add', [a, b]);
var mult = new OperatorNode('*', 'multiply', [a, b]);
var div = new OperatorNode('/', 'divide', [a, b]);
var n1= new OperatorNode('!', 'factorial', [sub] );
var n2= new OperatorNode('!', 'factorial', [add] );
var n3= new OperatorNode('!', 'factorial', [mult] );
var n4= new OperatorNode('!', 'factorial', [div] );
assert.equal(n1.toTex(), '\\left(2-3\\right)!');
assert.equal(n2.toTex(), '\\left(2+3\\right)!');
assert.equal(n3.toTex(), '\\left(2\\cdot3\\right)!');
assert.equal(n4.toTex(), '\\frac{2}{3}!');
});
it ('should LaTeX an OperatorNode with unary minus', function () {
var a = new ConstantNode(2);
var b = new ConstantNode(3);
var sub = new OperatorNode('-', 'subtract', [a, b]);
var add = new OperatorNode('+', 'add', [a, b]);
var n1 = new OperatorNode('-', 'unaryMinus', [a]);
var n2 = new OperatorNode('-', 'unaryMinus', [sub]);
var n3 = new OperatorNode('-', 'unaryMinus', [add]);
assert.equal(n1.toTex(), '-2');
assert.equal(n2.toTex(), '-\\left(2-3\\right)');
assert.equal(n3.toTex(), '-\\left(2+3\\right)');
});
it ('should LaTeX an OperatorNode that subtracts an OperatorNode', function() {
var a = new ConstantNode(1);
var b = new ConstantNode(2);
var c = new ConstantNode(3);
var sub = new OperatorNode('-', 'subtract', [b, c]);
var add = new OperatorNode('+', 'add', [b, c]);
var n1 = new OperatorNode('-', 'subtract', [a, sub]);
var n2 = new OperatorNode('-', 'subtract', [a, add]);
assert.equal(n1.toTex(), '1-\\left(2-3\\right)');
assert.equal(n2.toTex(), '1-\\left(2+3\\right)');
});
it ('should LaTeX an OperatorNode with zero arguments', function () {
var n = new OperatorNode('foo', 'foo', []);
assert.equal(n.toTex(), '\\mathrm{foo}\\left(\\right)');
});
it ('should LaTeX an OperatorNode with more than two operators', function () {
var a = new ConstantNode(2);
var b = new ConstantNode(3);
var c = new ConstantNode(4);
var n = new OperatorNode('foo', 'foo', [a, b, c]);
assert.equal(n.toTex(), '\\mathrm{foo}\\left(2,3,4\\right)');
});
it ('should LaTeX an OperatorNode with nested operator nodes', function () {
var a = new ConstantNode(2);
var b = new ConstantNode(3);
var c = new ConstantNode(4);
var d = new ConstantNode(5);
var n1 = new OperatorNode('+', 'add', [a, b]);
var n2 = new OperatorNode('-', 'subtract', [c, d]);
var n3 = new OperatorNode('*', 'multiply', [n1, n2]);
var m2 = new OperatorNode('*', 'multiply', [n1, c]);
var m3 = new OperatorNode('-', 'subtract', [m2, d]);
assert.equal(n1.toTex(), '2+3');
assert.equal(n2.toTex(), '4-5');
assert.equal(n3.toTex(), '\\left(2+3\\right)\\cdot\\left(4-5\\right)');
assert.equal(m3.toTex(), '\\left(2+3\\right)\\cdot4-5');
});
it ('should LaTeX addition and multiplication with more than two operands', function () {
var a = new SymbolNode('a');
var b = new SymbolNode('b');
var c = new SymbolNode('c');
var add = new OperatorNode('+', 'add', [a, b, c]);
var multiply = new OperatorNode('*', 'multiply', [a, b, c]);
var implicitMultiply = new OperatorNode('*', 'multiply', [a, b, c], true);
assert.equal(add.toTex(), ' a+\\mathrm{b}+ c');
assert.equal(multiply.toTex(), ' a\\cdot\\mathrm{b}\\cdot c');
assert.equal(implicitMultiply.toTex(), ' a~\\mathrm{b}~ c');
});
it ('should LaTeX addition and multiplication with more than two operands including OperatorNode', function () {
var a = new SymbolNode('a');
var b = new SymbolNode('b');
var c = new SymbolNode('c');
var d = new SymbolNode('d');
var mult = new OperatorNode('*', 'multiply', [a,b]);
var add = new OperatorNode('+', 'add', [a, b]);
var multipleMultWithMult = new OperatorNode('*', 'multiply', [c, mult, d]);
var multipleMultWithAdd = new OperatorNode('*', 'multiply', [c, add, d]);
var multipleAddWithMult = new OperatorNode('+', 'add', [c, mult, d]);
var multipleAddWithAdd = new OperatorNode('+', 'add', [c, add, d]);
assert.equal(multipleMultWithMult.toTex(), ' c\\cdot a\\cdot\\mathrm{b}\\cdot d');
assert.equal(multipleMultWithAdd.toTex(), ' c\\cdot\\left( a+\\mathrm{b}\\right)\\cdot d');
assert.equal(multipleAddWithMult.toTex(), ' c+ a\\cdot\\mathrm{b}+ d');
assert.equal(multipleAddWithAdd.toTex(), ' c+ a+\\mathrm{b}+ d');
});
it ('should LaTeX an OperatorNode that contains an operatornode with more than two operands', function () {
var a = new SymbolNode('a');
var b = new SymbolNode('b');
var c = new SymbolNode('c');
var d = new SymbolNode('d');
var mult = new OperatorNode('*', 'multiply', [a, b, c]);
var add = new OperatorNode('+', 'add', [a, b, c]);
var addWithMult = new OperatorNode('+', 'add', [mult, d]);
var addWithAdd = new OperatorNode('+', 'add', [add, d]);
var multWithMult = new OperatorNode('*', 'multiply', [mult, d]);
var multWithAdd = new OperatorNode('*', 'multiply', [add, d]);
assert.equal(addWithMult.toTex(), ' a\\cdot\\mathrm{b}\\cdot c+ d');
assert.equal(addWithAdd.toTex(), ' a+\\mathrm{b}+ c+ d');
assert.equal(multWithMult.toTex(), ' a\\cdot\\mathrm{b}\\cdot c\\cdot d');
assert.equal(multWithAdd.toTex(), '\\left( a+\\mathrm{b}+ c\\right)\\cdot d');
});
it('should LaTeX fractions with operators that are enclosed in parenthesis', function () {
var a = new ConstantNode(1);
var b = new ConstantNode(2);
var add = new OperatorNode('+', 'add', [a,a]);
var frac = new OperatorNode('/', 'divide', [add,b]);
assert.equal(frac.toTex(), '\\frac{1+1}{2}');
});
it ('should have an identifier', function () {
var a = new ConstantNode(1);
var b = new ConstantNode(2);
var n = new OperatorNode('+', 'add', [a, b]);
assert.equal(n.getIdentifier(), 'OperatorNode:add');
});
it ('should LaTeX an OperatorNode with custom toTex', function () {
//Also checks if the custom functions get passed on to the children
var customFunction = function (node, options) {
if (node.type === 'OperatorNode') {
return node.op + node.fn + '('
+ node.args[0].toTex(options)
+ ', ' + node.args[1].toTex(options) + ')';
}
else if (node.type === 'ConstantNode') {
return 'const\\left(' + node.value + ', ' + node.valueType + '\\right)'
}
};
var a = new ConstantNode(1);
var b = new ConstantNode(2);
var n1 = new OperatorNode('+', 'add', [a, b]);
var n2 = new OperatorNode('-', 'subtract', [a, b]);
assert.equal(n1.toTex({handler: customFunction}), '+add(const\\left(1, number\\right), const\\left(2, number\\right))');
assert.equal(n2.toTex({handler: customFunction}), '-subtract(const\\left(1, number\\right), const\\left(2, number\\right))');
});
it ('should LaTeX an OperatorNode with custom toTex for a single operator', function () {
//Also checks if the custom functions get passed on to the children
var customFunction = function (node, options) {
if ((node.type === 'OperatorNode') && (node.fn === 'add')) {
return node.args[0].toTex(options)
+ node.op + node.fn + node.op +
node.args[1].toTex(options);
}
else if (node.type === 'ConstantNode') {
return 'const\\left(' + node.value + ', ' + node.valueType + '\\right)'
}
};
var a = new ConstantNode(1);
var b = new ConstantNode(2);
var n = new OperatorNode('+', 'add', [a, b]);
assert.equal(n.toTex({handler: customFunction}), 'const\\left(1, number\\right)+add+const\\left(2, number\\right)');
});
it ('should LaTeX powers of fractions with parentheses', function () {
var a = new ConstantNode(1);
var frac = new OperatorNode('/', 'divide', [a,a]);
var pow = new OperatorNode('^', 'pow', [frac, a]);
assert.equal(pow.toTex(), '\\left({\\frac{1}{1}}\\right)^{1}');
});
it ('should LaTeX powers of conditions with parentheses', function () {
var a = new ConstantNode(1);
var cond = new ConditionalNode(a, a, a);
var pow = new OperatorNode('^', 'pow', [cond, a]);
assert.equal(pow.toTex(), '\\left({\\begin{cases} {1}, &\\quad{\\text{if }\\;1}\\\\{1}, &\\quad{\\text{otherwise}}\\end{cases}}\\right)^{1}');
});
it ('should LaTeX simple expressions in \'auto\' mode', function () {
//this covers a bug that was triggered previously
assert.equal(math.parse('1+(1+1)').toTex({parenthesis: 'auto'}), '1+1+1');
});
it ('should stringify implicit multiplications', function () {
var a = math.parse('4a');
var b = math.parse('4 a');
var c = math.parse('a b');
var d = math.parse('2a b');
var e = math.parse('a b c');
var f = math.parse('(2+3)a');
var g = math.parse('(2+3)2');
var h = math.parse('2(3+4)');
assert.equal(a.toString(), a.toString({implicit: 'hide'}));
assert.equal(a.toString({implicit: 'hide'}), '4 a');
assert.equal(a.toString({implicit: 'show'}), '4 * a');
assert.equal(b.toString(), b.toString({implicit: 'hide'}));
assert.equal(b.toString({implicit: 'hide'}), '4 a');
assert.equal(b.toString({implicit: 'show'}), '4 * a');
assert.equal(c.toString(), c.toString({implicit: 'hide'}));
assert.equal(c.toString({implicit: 'hide'}), 'a b');
assert.equal(c.toString({implicit: 'show'}), 'a * b');
assert.equal(d.toString(), d.toString({implicit: 'hide'}));
assert.equal(d.toString({implicit: 'hide'}), '2 a b');
assert.equal(d.toString({implicit: 'show'}), '2 * a * b');
assert.equal(e.toString(), e.toString({implicit: 'hide'}));
assert.equal(e.toString({implicit: 'hide'}), 'a b c');
assert.equal(e.toString({implicit: 'show'}), 'a * b * c');
assert.equal(f.toString(), f.toString({implicit: 'hide'}));
assert.equal(f.toString({implicit: 'hide'}), '(2 + 3) a');
assert.equal(f.toString({implicit: 'show'}), '(2 + 3) * a');
assert.equal(g.toString(), g.toString({implicit: 'hide'}));
assert.equal(g.toString({implicit: 'hide'}), '(2 + 3) 2');
assert.equal(g.toString({implicit: 'show'}), '(2 + 3) * 2');
assert.equal(h.toString(), h.toString({implicit: 'hide'}));
assert.equal(h.toString({implicit: 'hide'}), '2 (3 + 4)');
assert.equal(h.toString({implicit: 'show'}), '2 * (3 + 4)');
});
it ('should LaTeX implicit multiplications', function () {
var a = math.parse('4a');
var b = math.parse('4 a');
var c = math.parse('a b');
var d = math.parse('2a b');
var e = math.parse('a b c');
var f = math.parse('(2+3)a');
var g = math.parse('(2+3)2');
var h = math.parse('2(3+4)');
assert.equal(a.toTex(), a.toTex({implicit: 'hide'}));
assert.equal(a.toTex({implicit: 'hide'}), '4~ a');
assert.equal(a.toTex({implicit: 'show'}), '4\\cdot a');
assert.equal(b.toTex(), b.toTex({implicit: 'hide'}));
assert.equal(b.toTex({implicit: 'hide'}), '4~ a');
assert.equal(b.toTex({implicit: 'show'}), '4\\cdot a');
assert.equal(c.toTex(), c.toTex({implicit: 'hide'}));
assert.equal(c.toTex({implicit: 'hide'}), ' a~\\mathrm{b}');
assert.equal(c.toTex({implicit: 'show'}), ' a\\cdot\\mathrm{b}');
assert.equal(d.toTex(), d.toTex({implicit: 'hide'}));
assert.equal(d.toTex({implicit: 'hide'}), '2~ a~\\mathrm{b}');
assert.equal(d.toTex({implicit: 'show'}), '2\\cdot a\\cdot\\mathrm{b}');
assert.equal(e.toTex(), e.toTex({implicit: 'hide'}));
assert.equal(e.toTex({implicit: 'hide'}), ' a~\\mathrm{b}~ c');
assert.equal(e.toTex({implicit: 'show'}), ' a\\cdot\\mathrm{b}\\cdot c');
assert.equal(f.toTex(), f.toTex({implicit: 'hide'}));
assert.equal(f.toTex({implicit: 'hide'}), '\\left(2+3\\right)~ a');
assert.equal(f.toTex({implicit: 'show'}), '\\left(2+3\\right)\\cdot a');
assert.equal(g.toTex(), g.toTex({implicit: 'hide'}));
assert.equal(g.toTex({implicit: 'hide'}), '\\left(2+3\\right)~2');
assert.equal(g.toTex({implicit: 'show'}), '\\left(2+3\\right)\\cdot2');
assert.equal(h.toTex(), h.toTex({implicit: 'hide'}));
assert.equal(h.toTex({implicit: 'hide'}), '2~\\left(3+4\\right)');
assert.equal(h.toTex({implicit: 'show'}), '2\\cdot\\left(3+4\\right)');
});
});

View File

@@ -0,0 +1,199 @@
// test SymbolNode
var assert = require('assert');
var approx = require('../../../tools/approx');
var math = require('../../../index');
var Node = math.expression.node.Node;
var ConstantNode = math.expression.node.ConstantNode;
var OperatorNode = math.expression.node.OperatorNode;
var ParenthesisNode = math.expression.node.ParenthesisNode;
describe('ParenthesisNode', function() {
it ('should create a ParenthesisNode', function () {
var a = new ConstantNode(1);
var n = new ParenthesisNode(a);
assert(n instanceof ParenthesisNode);
assert(n instanceof Node);
assert.equal(n.type, 'ParenthesisNode');
});
it ('should throw an error when calling without new operator', function () {
var a = new ConstantNode(1);
assert.throws(function () {ParenthesisNode(a)}, SyntaxError);
});
it ('should throw an error when calling with wrong arguments', function () {
assert.throws(function () {new ParenthesisNode()}, TypeError);
assert.throws(function () {new ParenthesisNode(2)}, TypeError);
});
it ('should compile a ParenthesisNode', function () {
var a = new ConstantNode(1);
var n = new ParenthesisNode(a);
assert.equal(n.compile().eval.toString(), a.compile().eval.toString());
});
it ('should filter a ParenthesisNode', function () {
var a = new ConstantNode(1);
var n = new ParenthesisNode(a);
assert.deepEqual(n.filter(function (node) {return node instanceof ParenthesisNode;}), [n]);
assert.deepEqual(n.filter(function (node) {return node.content instanceof ConstantNode;}), [n]);
assert.deepEqual(n.filter(function (node) {
return (typeof node.content !== 'undefined') && (node.content.value == '1');
}), [n]);
assert.deepEqual(n.filter(function (node) {
return (typeof node.content !== 'undefined') && (node.content.type == 'ConstantNode');
}), [n]);
assert.deepEqual(n.filter(function (node) {return node instanceof ConstantNode;}), [a]);
});
it ('should run forEach on a ParenthesisNode', function () {
var count = 0;
var a = new ConstantNode(1);
var n = new ParenthesisNode(a);
n.forEach(function (node, path, _parent) {
assert.equal(node.type, 'ConstantNode');
assert.equal(path, 'content');
assert.deepEqual(_parent, n);
count++;
});
assert.equal(count, 1);
});
it ('should map a ParenthesisNode', function () {
var a = new ConstantNode(1);
var b = new ParenthesisNode(a);
var count = 0;
var c = b.map(function (node, path, _parent) {
count++;
assert.equal(node.type, 'ConstantNode');
assert.equal(node.value, 1);
return new ConstantNode(2);
});
assert.equal(count, 1);
assert.equal(c.content.value, 2);
});
it ('should transform a ParenthesisNode', function () {
var c1 = new ConstantNode(1);
var c2 = new ConstantNode(2);
var a = new ParenthesisNode(c1);
var b = new ParenthesisNode(c2);
var c = a.transform(function (node) {
return node instanceof ParenthesisNode && node.content.value == 1 ? b : node;
});
assert.deepEqual(c, b);
// no match should leave the constant as is
var d = a.transform(function (node) {
return node instanceof ParenthesisNode && node.name == 2 ? b : node;
});
assert.deepEqual(d, a);
});
it ('should clone a ParenthesisNode', function () {
var a = new ConstantNode(1);
var n = new ParenthesisNode(a);
var clone = n.clone();
assert(clone instanceof ParenthesisNode);
assert.deepEqual(n, clone);
assert.notStrictEqual(n, clone);
assert.equal(n.content, clone.content);
});
it ('test equality another Node', function () {
var a = new ParenthesisNode(new ConstantNode(1));
var b = new ParenthesisNode(new ConstantNode(1));
var c = new ParenthesisNode(new ConstantNode(2));
var d = new ConstantNode(2);
assert.strictEqual(a.equals(null), false);
assert.strictEqual(a.equals(undefined), false);
assert.strictEqual(a.equals(b), true);
assert.strictEqual(a.equals(c), false);
assert.strictEqual(a.equals(d), false);
});
it ('should get the content of a ParenthesisNode', function () {
var c = new math.expression.node.ConstantNode(1);
var p1 = new math.expression.node.ParenthesisNode(c);
var p2 = new math.expression.node.ParenthesisNode(p1);
assert.equal(p1.content, c);
assert.equal(p1.getContent(), c);
assert.deepEqual(p1.getContent(), c);
assert.equal(p2.getContent(), c);
assert.deepEqual(p2.getContent(), c);
});
it ('should stringify a ParenthesisNode', function () {
var a = new ConstantNode(1);
var n = new ParenthesisNode(a);
assert.equal(n.toString(), '(1)');
assert.equal(n.toString({}), '(1)');
});
it ('should stringify a ParenthesisNode when not in keep mode', function () {
var c = new math.expression.node.ConstantNode(1);
var p = new math.expression.node.ParenthesisNode(c);
assert.equal(p.toString({parenthesis: 'all'}), '1');
assert.equal(p.toString({parenthesis: 'auto'}), '1');
});
it ('should stringify a ParenthesisNode with custom toString', function () {
var customFunction = function (node, options) {
if (node.type === 'ParenthesisNode') {
return '[' + node.content.toString(options) + ']';
}
};
var c = new math.expression.node.ConstantNode(1);
var n = new math.expression.node.ParenthesisNode(c);
assert.equal(n.toString({handler: customFunction}), '[1]');
});
it ('should LaTeX a ParenthesisNode', function () {
var a = new ConstantNode(1);
var n = new ParenthesisNode(a);
assert.equal(n.toTex(), '\\left(1\\right)');
assert.equal(n.toTex({}), '\\left(1\\right)');
});
it ('should LaTeX a ParenthesisNode when not in keep mode', function () {
var c = new math.expression.node.ConstantNode(1);
var p = new math.expression.node.ParenthesisNode(c);
assert.equal(p.toTex({parenthesis: 'all'}), '1');
assert.equal(p.toTex({parenthesis: 'auto'}), '1');
});
it ('should LaTeX a ParenthesisNode with custom toTex', function () {
var customFunction = function (node, options) {
if (node.type === 'ParenthesisNode') {
return '\\left[' + node.content.toTex(options) + '\\right]';
}
};
var c = new math.expression.node.ConstantNode(1);
var n = new math.expression.node.ParenthesisNode(c);
assert.equal(n.toTex({handler: customFunction}), '\\left[1\\right]');
});
});

View File

@@ -0,0 +1,376 @@
// test RangeNode
var assert = require('assert');
var approx = require('../../../tools/approx');
var math = require('../../../index');
var Node = math.expression.node.Node;
var ConstantNode = math.expression.node.ConstantNode;
var SymbolNode = math.expression.node.SymbolNode;
var RangeNode = math.expression.node.RangeNode;
var OperatorNode = math.expression.node.OperatorNode;
describe('RangeNode', function() {
it ('should create a RangeNode', function () {
var start = new ConstantNode(0);
var end = new ConstantNode(10);
var n = new RangeNode(start, end);
assert(n instanceof RangeNode);
assert(n instanceof Node);
assert.equal(n.type, 'RangeNode');
});
it ('should have isRangeNode', function () {
var start = new ConstantNode(0);
var end = new ConstantNode(10);
var node = new RangeNode(start, end);
assert(node.isRangeNode);
});
it ('should throw an error when calling without new operator', function () {
var start = new ConstantNode(0);
var end = new ConstantNode(10);
assert.throws(function () {RangeNode([start, end])}, SyntaxError);
});
it ('should throw an error creating a RangeNode with wrong number or type of arguments', function () {
var start = new ConstantNode(0);
var end = new ConstantNode(10);
assert.throws(function () { new RangeNode(); }, TypeError);
assert.throws(function () { new RangeNode(start); }, TypeError);
assert.throws(function () { new RangeNode([]); }, TypeError);
assert.throws(function () { new RangeNode(start, end, start, end); }, Error);
assert.throws(function () { new RangeNode(0, 10); }, TypeError);
});
it ('should compile a RangeNode', function () {
var start = new ConstantNode(0);
var end = new ConstantNode(10);
var step = new ConstantNode(2);
var n = new RangeNode(start, end, step);
var expr = n.compile();
assert.deepEqual(expr.eval(), math.matrix([0, 2, 4, 6, 8, 10]));
});
it ('should filter a RangeNode', function () {
var start = new ConstantNode(0);
var end = new ConstantNode(10);
var step = new ConstantNode(2);
var n = new RangeNode(start, end, step);
assert.deepEqual(n.filter(function (node) {return node instanceof RangeNode}), [n]);
assert.deepEqual(n.filter(function (node) {return node instanceof SymbolNode}), []);
assert.deepEqual(n.filter(function (node) {return node instanceof ConstantNode}), [start, end, step]);
assert.deepEqual(n.filter(function (node) {return node instanceof ConstantNode && node.value == '2'}), [step]);
assert.deepEqual(n.filter(function (node) {return node instanceof ConstantNode && node.value == '4'}), []);
});
it ('should run forEach on a RangeNode', function () {
var start = new ConstantNode(0);
var end = new ConstantNode(10);
var step = new ConstantNode(2);
var n = new RangeNode(start, end, step);
var nodes = [];
var paths = [];
n.forEach(function (node, path, parent) {
nodes.push(node);
paths.push(path);
assert.strictEqual(parent, n);
});
assert.equal(nodes.length, 3);
assert.strictEqual(nodes[0], start);
assert.strictEqual(nodes[1], end);
assert.strictEqual(nodes[2], step);
assert.deepEqual(paths, ['start', 'end', 'step']);
});
it ('should map a RangeNode', function () {
var start = new ConstantNode(0);
var end = new ConstantNode(10);
var step = new ConstantNode(2);
var n = new RangeNode(start, end, step);
var nodes = [];
var paths = [];
var e = new ConstantNode(3);
var f = n.map(function (node, path, parent) {
nodes.push(node);
paths.push(path);
assert.strictEqual(parent, n);
return node instanceof ConstantNode && node.value == '0' ? e : node;
});
assert.equal(nodes.length, 3);
assert.strictEqual(nodes[0], start);
assert.strictEqual(nodes[1], end);
assert.strictEqual(nodes[2], step);
assert.deepEqual(paths, ['start', 'end', 'step']);
assert.notStrictEqual(f, n);
assert.deepEqual(f.start, e);
assert.deepEqual(f.end, end);
assert.deepEqual(f.step, step);
});
it ('should throw an error when the map callback does not return a node', function () {
var start = new ConstantNode(0);
var end = new ConstantNode(10);
var step = new ConstantNode(2);
var n = new RangeNode(start, end, step);
assert.throws(function () {
n.map(function () {});
}, /Callback function must return a Node/)
});
it ('should transform a RangeNodes start', function () {
var start = new ConstantNode(0);
var end = new ConstantNode(10);
var step = new ConstantNode(2);
var n = new RangeNode(start, end, step);
var e = new ConstantNode(3);
var f = n.transform(function (node) {
return node instanceof ConstantNode && node.value == '0' ? e : node;
});
assert.notStrictEqual(f, n);
assert.deepEqual(f.start, e);
assert.deepEqual(f.end, end);
assert.deepEqual(f.step, step);
});
it ('should transform a RangeNodes end', function () {
var start = new ConstantNode(0);
var end = new ConstantNode(10);
var step = new ConstantNode(2);
var n = new RangeNode(start, end, step);
var e = new ConstantNode(3);
var f = n.transform(function (node) {
return node instanceof ConstantNode && node.value == '10' ? e : node;
});
assert.notStrictEqual(f, n);
assert.deepEqual(f.start, start);
assert.deepEqual(f.end, e);
assert.deepEqual(f.step, step);
});
it ('should transform a RangeNodes step', function () {
var start = new ConstantNode(0);
var end = new ConstantNode(10);
var step = new ConstantNode(2);
var n = new RangeNode(start, end, step);
var e = new ConstantNode(3);
var f = n.transform(function (node) {
return node instanceof ConstantNode && node.value == '2' ? e : node;
});
assert.notStrictEqual(f, n);
assert.deepEqual(f.start, start);
assert.deepEqual(f.end, end);
assert.deepEqual(f.step, e);
});
it ('should transform a RangeNodes without step', function () {
var start = new ConstantNode(0);
var end = new ConstantNode(10);
var n = new RangeNode(start, end);
var e = new ConstantNode(3);
var f = n.transform(function (node) {
return node instanceof ConstantNode && node.value == '10' ? e : node;
});
assert.notStrictEqual(f, n);
assert.deepEqual(f.start, start);
assert.deepEqual(f.end, e);
});
it ('should transform a RangeNode itself', function () {
var start = new ConstantNode(0);
var end = new ConstantNode(10);
var step = new ConstantNode(2);
var n = new RangeNode(start, end, step);
var e = new ConstantNode(5);
var f = n.transform(function (node) {
return node instanceof RangeNode ? e : node;
});
assert.deepEqual(f, e);
});
it ('should clone a RangeNode', function () {
var start = new ConstantNode(0);
var end = new ConstantNode(10);
var step = new ConstantNode(2);
var c = new RangeNode(start, end, step);
var d = c.clone();
assert.deepEqual(d, c);
assert.notStrictEqual(d, c);
assert.strictEqual(d.start, c.start);
assert.strictEqual(d.end, c.end);
assert.strictEqual(d.step, c.step);
});
it ('should clone a RangeNode without step', function () {
var start = new ConstantNode(0);
var end = new ConstantNode(10);
var c = new RangeNode(start, end);
var d = c.clone();
assert(d instanceof RangeNode);
assert.deepEqual(d, c);
assert.notStrictEqual(d, c);
assert.strictEqual(d.start, c.start);
assert.strictEqual(d.end, c.end);
assert.strictEqual(d.step, c.step);
assert.strictEqual(d.step, null);
});
it ('test equality another Node', function () {
assert.strictEqual(createRangeNode(2, 4).equals(createRangeNode(2, 4)), true);
assert.strictEqual(createRangeNode(2, 4).equals(createRangeNode(2, 5)), false);
assert.strictEqual(createRangeNode(2, 4).equals(createRangeNode(2, 4, 1)), false);
assert.strictEqual(createRangeNode(2, 4).equals(createRangeNode(2, 4, -1)), false);
assert.strictEqual(createRangeNode(2, 4, -1).equals(createRangeNode(2, 4, -1)), true);
assert.strictEqual(createRangeNode(2, 4, -1).equals(null), false);
assert.strictEqual(createRangeNode(2, 4, -1).equals(undefined), false);
assert.strictEqual(createRangeNode(2, 4, -1).equals(new SymbolNode('a')), false);
assert.strictEqual(createRangeNode(2, 4, -1).equals(new SymbolNode('a')), false);
});
it ('should stringify a RangeNode without step', function () {
var start = new ConstantNode(0);
var end = new ConstantNode(10);
var n = new RangeNode(start, end);
assert.equal(n.toString(), '0:10');
});
it ('should stringify a RangeNode with step', function () {
var start = new ConstantNode(0);
var end = new ConstantNode(10);
var step = new ConstantNode(2);
var n = new RangeNode(start, end, step);
assert.equal(n.toString(), '0:2:10');
});
it ('should stringify a RangeNode with an OperatorNode', function () {
var a = new ConstantNode(1);
var b = new ConstantNode(2);
var o1 = new OperatorNode('+', 'add', [a, b]);
var o2 = new OperatorNode('<', 'smaller', [a, b]);
var n = new RangeNode(o1, o1, o2);
assert.equal(n.toString(), '1 + 2:(1 < 2):1 + 2');
});
it ('should stringify a RangeNode with a RangeNode', function () {
var start1 = new ConstantNode(0);
var end1 = new ConstantNode(10);
var step2 = new ConstantNode(2);
var end2 = new ConstantNode(100);
var start2 = new RangeNode(start1, end1);
var n = new RangeNode(start2, end2, step2);
assert.equal(n.toString(), '(0:10):2:100');
});
it ('should stringify a RangeNode with custom toString', function () {
//Also checks if the custom functions get passed on to the children
var customFunction = function (node, options) {
if (node.type === 'RangeNode') {
return 'from ' + node.start.toString(options)
+ ' to ' + node.end.toString(options)
+ ' with steps of ' + node.step.toString(options);
}
else if (node.type === 'ConstantNode') {
return 'const(' + node.value + ', ' + node.valueType + ')'
}
};
var a = new ConstantNode(1);
var b = new ConstantNode(2);
var c = new ConstantNode(3);
var n = new RangeNode(a, b, c);
assert.equal(n.toString({handler: customFunction}), 'from const(1, number) to const(2, number) with steps of const(3, number)');
});
it ('should respect the \'all\' parenthesis option', function () {
assert.equal(math.parse('1:2:3').toString({parenthesis: 'all'}), '(1):(2):(3)');
assert.equal(math.parse('1:2:3').toTex({parenthesis: 'all'}), '\\left(1\\right):\\left(2\\right):\\left(3\\right)');
});
it ('should LaTeX a RangeNode without step', function () {
var start = new ConstantNode(0);
var end = new ConstantNode(10);
var n = new RangeNode(start, end);
assert.equal(n.toTex(), '0:10');
});
it ('should LaTeX a RangeNode with step', function () {
var start = new ConstantNode(0);
var end = new ConstantNode(10);
var step = new ConstantNode(2);
var n = new RangeNode(start, end, step);
assert.equal(n.toTex(), '0:2:10');
});
it ('should LaTeX a RangeNode with custom toTex', function () {
//Also checks if the custom functions get passed on to the children
var customFunction = function (node, options) {
if (node.type === 'RangeNode') {
return 'from ' + node.start.toTex(options)
+ ' to ' + node.end.toTex(options)
+ ' with steps of ' + node.step.toTex(options);
}
else if (node.type === 'ConstantNode') {
return 'const\\left(' + node.value + ', ' + node.valueType + '\\right)'
}
};
var a = new ConstantNode(1);
var b = new ConstantNode(2);
var c = new ConstantNode(3);
var n = new RangeNode(a, b, c);
assert.equal(n.toTex({handler: customFunction}), 'from const\\left(1, number\\right) to const\\left(2, number\\right) with steps of const\\left(3, number\\right)');
});
/**
* Helper function to create a RangeNode
* @param {number} start
* @param {number} end
* @param {number} [step]
* @return {RangeNode}
*/
function createRangeNode(start, end, step) {
if (step === undefined) {
return new RangeNode(new ConstantNode(start), new ConstantNode(end));
}
else {
return new RangeNode(new ConstantNode(start), new ConstantNode(end), new ConstantNode(step));
}
}
});

View File

@@ -0,0 +1,167 @@
// test SymbolNode
var assert = require('assert');
var approx = require('../../../tools/approx');
var math = require('../../../index');
var Node = math.expression.node.Node;
var ConstantNode = math.expression.node.ConstantNode;
var SymbolNode = math.expression.node.SymbolNode;
var OperatorNode = math.expression.node.OperatorNode;
describe('SymbolNode', function() {
it ('should create a SymbolNode', function () {
var n = new SymbolNode('sqrt');
assert(n instanceof SymbolNode);
assert(n instanceof Node);
assert.equal(n.type, 'SymbolNode');
});
it ('should have isSymbolNode', function () {
var node = new SymbolNode('a');
assert(node.isSymbolNode);
});
it ('should throw an error when calling without new operator', function () {
assert.throws(function () {SymbolNode('sqrt')}, SyntaxError);
});
it ('should throw an error when calling with wrong arguments', function () {
assert.throws(function () {new SymbolNode()}, TypeError);
assert.throws(function () {new SymbolNode(2)}, TypeError);
});
it ('should throw an error when evaluating an undefined symbol', function () {
var scope = {};
var s = new SymbolNode('foo');
assert.throws(function () {s.compile().eval(scope)}, Error);
});
it ('should compile a SymbolNode', function () {
var s = new SymbolNode('a');
var expr = s.compile();
var scope = {a: 5};
assert.equal(expr.eval(scope), 5);
assert.throws(function () {expr.eval({})}, Error);
var s2 = new SymbolNode('sqrt');
var expr2 = s2.compile();
var scope2 = {};
assert.strictEqual(expr2.eval(scope2), math.sqrt);
});
it ('should filter a SymbolNode', function () {
var n = new SymbolNode('x');
assert.deepEqual(n.filter(function (node) {return node instanceof SymbolNode}), [n]);
assert.deepEqual(n.filter(function (node) {return node.name == 'x'}), [n]);
assert.deepEqual(n.filter(function (node) {return node.name == 'q'}), []);
assert.deepEqual(n.filter(function (node) {return node instanceof ConstantNode}), []);
});
it ('should run forEach on a SymbolNode', function () {
var a = new SymbolNode('a');
a.forEach(function () {
assert.ok(false, 'should not execute, symbol has no childs')
});
});
it ('should map a SymbolNode', function () {
var a = new SymbolNode('a');
var c = new SymbolNode('c');
var b = a.map(function () {
assert.ok(false, 'should not execute, symbol has no childs')
});
assert.notStrictEqual(b, a);
assert.deepEqual(b, a);
});
it ('should transform a SymbolNode', function () {
var a = new SymbolNode('x');
var b = new SymbolNode('y');
var c = a.transform(function (node) {
return node instanceof SymbolNode && node.name == 'x' ? b : node;
});
assert.deepEqual(c, b);
// no match should leave the symbol as is
var d = a.transform(function (node) {
return node instanceof SymbolNode && node.name == 'q' ? b : node;
});
assert.deepEqual(d, a);
});
it ('should clone a SymbolNode', function () {
var a = new SymbolNode('x');
var b = a.clone();
assert(b instanceof SymbolNode);
assert.deepEqual(a, b);
assert.notStrictEqual(a, b);
assert.equal(a.name, b.name);
});
it ('test equality another Node', function () {
var a = new SymbolNode('a');
var b = new SymbolNode('b');
var aEqual = new SymbolNode('a');
var aFake = {
name: 'a'
};
assert.strictEqual(a.equals(null), false);
assert.strictEqual(a.equals(undefined), false);
assert.strictEqual(a.equals(aEqual), true);
assert.strictEqual(a.equals(b), false);
assert.strictEqual(a.equals(aFake), false);
assert.strictEqual(a.equals(new ConstantNode(2)), false);
});
it ('should stringify a SymbolNode', function () {
var s = new SymbolNode('foo');
assert.equal(s.toString(), 'foo');
});
it ('should stringigy a SymbolNode with custom toString', function () {
//Also checks if the custom functions get passed on to the children
var customFunction = function (node, options) {
if (node.type === 'SymbolNode') {
return 'symbol(' + node.name + ')';
}
};
var n = new SymbolNode('a');
assert.equal(n.toString({handler: customFunction}), 'symbol(a)');
});
it ('should LaTeX a SymbolNode', function () {
var s = new SymbolNode('foo');
assert.equal(s.toTex(), ' foo');
});
it ('should LaTeX a SymbolNode with custom toTex', function () {
//Also checks if the custom functions get passed on to the children
var customFunction = function (node, options) {
if (node.type === 'SymbolNode') {
return 'symbol(' + node.name + ')';
}
};
var n = new SymbolNode('a');
assert.equal(n.toTex({handler: customFunction}), 'symbol(a)');
});
it ('should LaTeX a SymbolNode without breaking \\cdot', function () {
var a = new ConstantNode(1);
var b = new SymbolNode('Epsilon');
var mult = new OperatorNode('*', 'multiply', [a,b]);
assert.equal(mult.toTex(), '1\\cdot E');
});
});

View File

@@ -0,0 +1,11 @@
// test the contents of index.js
var assert = require('assert');
var index = require('../../../lib/expression/node/index');
describe('node/index', function() {
it('should contain all nodes', function() {
assert.equal(index.length, 16);
});
});

View File

@@ -0,0 +1,114 @@
var assert = require('assert');
var math = require('../../index');
var operators = require('../../lib/expression/operators');
var OperatorNode = math.expression.node.OperatorNode;
var AssignmentNode = math.expression.node.AssignmentNode;
var SymbolNode = math.expression.node.SymbolNode;
var ConstantNode = math.expression.node.ConstantNode;
var Node = math.expression.node.Node;
var ParenthesisNode = math.expression.node.ParenthesisNode;
describe('operators', function () {
it('should return the precedence of a node', function () {
var a = new ConstantNode(1);
var b = new ConstantNode(2);
var n1 = new AssignmentNode(new SymbolNode('a'), a);
var n2 = new OperatorNode('or', 'or', [a, b]);
assert.equal(operators.getPrecedence(n1, 'keep'), 0);
assert.equal(operators.getPrecedence(n2, 'keep'), 2);
});
it('should return null if precedence is not defined for a node', function () {
var n = new Node();
assert.equal(operators.getPrecedence(n, 'keep'), null);
});
it ('should return the precedence of a ParenthesisNode', function () {
var c = new ConstantNode(1);
var op = new OperatorNode('or', 'or', [c, c]);
var p = new ParenthesisNode(op);
assert.equal(operators.getPrecedence(p, 'all'), operators.getPrecedence(op, 'all'));
assert.equal(operators.getPrecedence(p, 'auto'), operators.getPrecedence(op, 'all'));
assert.equal(operators.getPrecedence(p, 'keep'), null);
});
it('should return the associativity of a node', function () {
var a = new ConstantNode(1);
var n1 = new OperatorNode('+', 'add', [a, a]);
var n2 = new OperatorNode('^', 'pow', [a, a]);
var n3 = new OperatorNode('-', 'unaryMinus', [a]);
var n4 = new OperatorNode('!', 'factorial', [a]);
assert.equal(operators.getAssociativity(n1, 'keep'), 'left');
assert.equal(operators.getAssociativity(n2, 'keep'), 'right');
assert.equal(operators.getAssociativity(n3, 'keep'), 'right');
assert.equal(operators.getAssociativity(n4, 'keep'), 'left');
});
it ('should return the associativity of a ParenthesisNode', function () {
var c = new ConstantNode(1);
var op = new OperatorNode('or', 'or', [c, c]);
var p = new ParenthesisNode(op);
assert.equal(operators.getAssociativity(p, 'all'), operators.getAssociativity(op, 'keep'));
assert.equal(operators.getAssociativity(p, 'auto'), operators.getAssociativity(op, 'keep'));
assert.equal(operators.getAssociativity(p, 'keep'), null);
});
it('should return null if associativity is not defined for a node', function () {
var a = new ConstantNode(1);
var n1 = new Node();
var n2 = new AssignmentNode(new SymbolNode('a'), a);
assert.equal(operators.getAssociativity(n1, 'keep'), null);
assert.equal(operators.getAssociativity(n2, 'keep'), null);
});
it('should return if a Node is associative with another Node', function () {
var a = new ConstantNode(1);
var n1 = new OperatorNode('+', 'add', [a, a]);
var n2 = new OperatorNode('-', 'subtract', [a, a]);
assert.equal(operators.isAssociativeWith(n1, n1, 'keep'), true);
assert.equal(operators.isAssociativeWith(n1, n2, 'keep'), true);
assert.equal(operators.isAssociativeWith(n2, n2, 'keep'), false);
assert.equal(operators.isAssociativeWith(n2, n1, 'keep'), false);
});
it('should return null if the associativity between two Nodes is not defined', function () {
var a = new ConstantNode(1);
var n1 = new Node();
var n2 = new AssignmentNode(new SymbolNode('a'), a);
assert.equal(operators.isAssociativeWith(n1, n1, 'keep'), null);
assert.equal(operators.isAssociativeWith(n1, n2, 'keep'), null);
assert.equal(operators.isAssociativeWith(n2, n2, 'keep'), null);
assert.equal(operators.isAssociativeWith(n2, n1, 'keep'), null);
});
it ('should return if a ParenthesisNode is associative with another Node', function () {
var a = new ConstantNode(1);
var add = new OperatorNode('+', 'add', [a, a]);
var sub = new OperatorNode('-', 'subtract', [a, a]);
var p = new ParenthesisNode(add);
assert.equal(operators.isAssociativeWith(p, sub, 'all'), true);
assert.equal(operators.isAssociativeWith(p, sub, 'auto'), true);
assert.equal(operators.isAssociativeWith(p, sub, 'keep'), null);
});
});

View File

@@ -0,0 +1,2044 @@
// test parse
var assert = require('assert');
var approx = require('../../tools/approx');
var math = require('../../index');
var ArgumentsError = require('../../lib/error/ArgumentsError');
var parse = math.expression.parse;
var ConditionalNode = math.expression.node.ConditionalNode;
var OperatorNode = math.expression.node.OperatorNode;
var RangeNode = math.expression.node.RangeNode;
var Complex = math.type.Complex;
var Matrix = math.type.Matrix;
var Range = math.type.Range;
var Unit = math.type.Unit;
var ResultSet = math.type.ResultSet;
/**
* Helper function to parse an expression and immediately evaluate its results
* @param {String} expr
* @param {Object} [scope]
* @return {*} result
*/
function parseAndEval(expr, scope) {
return parse(expr).eval(scope);
}
describe('parse', function() {
it('should parse a single expression', function() {
approx.equal(parse('2 + 6 / 3').compile().eval(), 4);
});
it('should parse an empty expression', function() {
assert.strictEqual(parse('').compile().eval(), undefined);
assert.strictEqual(parse('\n').compile().eval(), undefined);
assert.strictEqual(parse('\n\n').compile().eval(), undefined);
assert.strictEqual(parse('\n \n').compile().eval(), undefined);
assert.strictEqual(parse('#foo\n').compile().eval(), undefined);
assert.strictEqual(parse('#foo\n#bar\n').compile().eval(), undefined);
});
it('should parse an array with expressions', function() {
var scope = {};
assert.deepEqual(parse(['a=3', 'b=4', 'a*b']).map(function (node) {
return node.compile().eval(scope);
}), [3, 4, 12]);
});
it('should parse a matrix with expressions', function() {
var scope = {};
assert.deepEqual(parse(math.matrix(['a=3', 'b=4', 'a*b'])).map(function (node) {
return node.compile().eval(scope);
}), math.matrix([3, 4, 12]));
});
it('should parse an array with an empty expression', function() {
assert.deepEqual(parse(['']).map(function (node) {
return node.compile().eval();
}), [undefined]);
});
it('should parse an array with an empty expression', function() {
assert.deepEqual(parse(math.matrix([''])).map(function (node) {
return node.compile().eval();
}), math.matrix([undefined]));
});
it('should parse unicode characters', function() {
// http://unicode-table.com/en
var scope = {};
math.eval('\u00E9 = 2', scope); // Latin Small Letter E with Acute
assert.strictEqual(scope['\u00E9'], 2);
math.eval('\u03A6 = 3', scope); // Greek Capital Letter Phi
assert.strictEqual(scope['\u03A6'], 3);
math.eval('\u03A9 = 4', scope); // Greek Capital Letter Omega
assert.strictEqual(scope['\u03A9'], 4);
math.eval('\u2126 = 4', scope); // Letter-like character Ohm
assert.strictEqual(scope['\u2126'], 4);
math.eval('k\u00F6ln = 5', scope); // Combination of latin and unicode
assert.strictEqual(scope['k\u00F6ln'], 5);
// test unicode characters in the astral plane (surrogate pairs
math.eval('\uD835\uDD38 = 1', scope); // double struck capital A
assert.strictEqual(scope['\uD835\uDD38'], 1);
// should not allow the "holes"
assert.throws(function () {
math.eval('\uD835\uDCA3 = 1', scope);
})
});
describe('multiline', function () {
it('should parse multiline expressions', function() {
assert.deepEqual(parse('a=3\nb=4\na*b').compile().eval(), new ResultSet([3, 4, 12]));
assert.deepEqual(parse('b = 43; b * 4').compile().eval(), new ResultSet([172]));
});
it('should skip empty lines in multiline expressions', function() {
assert.deepEqual(parse('\n;\n2 * 4\n').compile().eval(), new ResultSet([8]));
});
it('should spread operators over multiple lines', function() {
assert.deepEqual(parse('2+\n3').compile().eval(), 5);
assert.deepEqual(parse('2+\n\n3').compile().eval(), 5);
assert.deepEqual(parse('2*\n3').compile().eval(), 6);
assert.deepEqual(parse('2^\n3').compile().eval(), 8);
assert.deepEqual(parse('2==\n3').compile().eval(), false);
assert.deepEqual(parse('2*-\n3').compile().eval(), -6);
});
it('should parse multiple function assignments', function() {
var scope = {};
parse('f(x)=x*2;g(x)=x*3').compile().eval(scope);
assert.equal(scope.f(2), 4);
assert.equal(scope.g(2), 6);
var scope2 = {};
parse('a=2;f(x)=x^a;').compile().eval(scope2);
assert.equal(scope2.a, 2);
assert.equal(scope2.f(3), 9);
});
it ('should correctly scope a function variable if also used outside the function', function () {
var scope = {};
var res = parse('x=2;f(x)=x^2;x').compile().eval(scope); // x should be x=2, not x of the function
assert.deepEqual(res, {entries: [2]});
assert.equal(scope.x, 2);
assert.equal(scope.f(3), 9);
});
it('should spread a function over multiple lines', function() {
assert.deepEqual(parse('add(\n4\n,\n2\n)').compile().eval(), 6);
});
it('should spread contents of parameters over multiple lines', function() {
assert.deepEqual(parse('(\n4\n+\n2\n)').compile().eval(), 6);
});
it('should spread a function assignment over multiple lines', function() {
assert.deepEqual(typeof parse('f(\nx\n,\ny\n)=\nx+\ny').compile().eval(), 'function');
});
it('should spread a variable assignment over multiple lines', function() {
assert.deepEqual(parse('x=\n2').compile().eval(), 2);
});
it('should spread a matrix over multiple lines', function() {
assert.deepEqual(parse('[\n1\n,\n2\n]').compile().eval(), math.matrix([1, 2]));
});
it('should spread a range over multiple lines', function() {
assert.deepEqual(parse('2:\n4').compile().eval(), math.matrix([2,3,4]));
assert.deepEqual(parse('2:\n2:\n6').compile().eval(), math.matrix([2,4,6]));
});
it('should spread an index over multiple lines', function() {
assert.deepEqual(parse('a[\n1\n,\n1\n]').compile().eval({a: [[1,2],[3,4]]}), 1);
var scope = {a: [[1,2],[3,4]]};
assert.deepEqual(parse('a[\n1\n,\n1\n]=\n100').compile().eval(scope), 100);
assert.deepEqual(scope, {a: [[100,2],[3,4]]})
});
});
it('should throw an error when scope contains a reserved keyword', function() {
var scope = {
end: 2
};
assert.throws(function () {
parse('2+3').compile().eval(scope);
}, /Scope contains an illegal symbol/);
});
it('should give informative syntax errors', function() {
assert.throws(function () {parse('2 +');}, /Unexpected end of expression \(char 4\)/);
assert.throws(function () {parse('2 + 3 + *');}, /Value expected \(char 9\)/);
});
it('should throw an error if called with wrong number of arguments', function() {
assert.throws(function () {parse();}, ArgumentsError);
assert.throws(function () {parse(1,2,3);}, ArgumentsError);
assert.throws(function () {parse([1, 2]);}, TypeError);
});
it('should throw an error if called with a wrong type of argument', function() {
assert.throws(function () {parse(23);}, TypeError);
assert.throws(function () {parse(math.unit('5cm'));}, TypeError);
assert.throws(function () {parse(new Complex(2,3));}, TypeError);
assert.throws(function () {parse(true);}, TypeError);
});
it('should throw an error in case of unsupported characters', function() {
assert.throws(function () {parse('2\u00A1');}, /Syntax error in part "\u00A1"/);
});
describe('comments', function () {
it('should skip comments', function() {
assert.equal(parseAndEval('2 + 3 # - 4'), 5);
});
it('should skip comments in a ResultSet', function() {
assert.deepEqual(parseAndEval('2 + 3 # - 4\n6-2'), new ResultSet([5, 4]));
});
it('should fill in the property comment of a Node', function() {
assert.equal(parse('2 + 3').comment, '');
assert.equal(parse('2 + 3 # hello').comment, '# hello');
assert.equal(parse(' # hi').comment, '# hi');
var blockNode = parse('2 # foo\n3 # bar');
assert.equal(blockNode.blocks.length, 2);
assert.equal(blockNode.blocks[0].node.comment, '# foo');
assert.equal(blockNode.blocks[1].node.comment, '# bar');
});
});
describe('number', function () {
it('should parse valid numbers', function() {
assert.equal(parseAndEval('0'), 0);
assert.equal(parseAndEval('3'), 3);
assert.equal(parseAndEval('3.2'), 3.2);
assert.equal(parseAndEval('3.'), 3);
assert.equal(parseAndEval('3. '), 3);
assert.equal(parseAndEval('3.\t'), 3);
assert.equal(parseAndEval('003.2'), 3.2);
assert.equal(parseAndEval('003.200'), 3.2);
assert.equal(parseAndEval('.2'), 0.2);
assert.equal(parseAndEval('3e2'), 300);
assert.equal(parseAndEval('300e2'), 30000);
assert.equal(parseAndEval('300e+2'), 30000);
assert.equal(parseAndEval('300e-2'), 3);
assert.equal(parseAndEval('300E-2'), 3);
assert.equal(parseAndEval('3.2e2'), 320);
});
it('should parse a number followed by e', function() {
approx.equal(parseAndEval('2e'), 2 * Math.E);
});
it('should throw an error with invalid numbers', function() {
assert.throws(function () {parseAndEval('.'); }, /Value expected/);
assert.throws(function () {parseAndEval('3.2.2'); }, SyntaxError);
assert.throws(function () {parseAndEval('3.2e2.2'); }, SyntaxError);
assert.throws(function () {parseAndEval('3e0.5'); }, /Digit expected, got "."/);
assert.throws(function () {parseAndEval('3e.5'); }, /Digit expected, got "."/);
assert.throws(function () {parseAndEval('-3e0.5'); }, /Digit expected, got "."/);
assert.throws(function () {parseAndEval('-3e.5'); }, /Digit expected, got "."/);
assert.throws(function () {parseAndEval('3e-0.5'); }, /Digit expected, got "."/);
assert.throws(function () {parseAndEval('3e-.5'); }, /Digit expected, got "."/);
assert.throws(function () {parseAndEval('-3e-0.5'); }, /Digit expected, got "."/);
assert.throws(function () {parseAndEval('-3e-.5'); }, /Digit expected, got "."/);
assert.throws(function () {parseAndEval('2e+a'); }, /Digit expected, got "a"/);
});
});
describe('bignumber', function () {
it('should parse bignumbers', function() {
assert.deepEqual(parseAndEval('bignumber(0.1)'), math.bignumber(0.1));
assert.deepEqual(parseAndEval('bignumber("1.2e500")'), math.bignumber('1.2e500'));
});
it('should output bignumbers if default number type is bignumber', function() {
var bigmath = math.create({
number: 'BigNumber'
});
assert.deepEqual(bigmath.parse('0.1').compile().eval(), bigmath.bignumber(0.1));
assert.deepEqual(bigmath.parse('1.2e5000').compile().eval(), bigmath.bignumber('1.2e5000'));
});
});
describe('fraction', function () {
it('should output fractions if default number type is fraction', function() {
var fmath = math.create({
number: 'Fraction'
});
assert(fmath.parse('0.1').compile().eval() instanceof math.type.Fraction);
assert.equal(fmath.parse('1/3').compile().eval().toString(), '0.(3)');
assert.equal(fmath.parse('0.1+0.2').compile().eval().toString(), '0.3');
});
});
describe('string', function () {
it('should parse a string', function() {
assert.deepEqual(parseAndEval('"hello"'), "hello");
assert.deepEqual(parseAndEval(' "hi" '), "hi");
});
it('should parse a with escaped characters', function() {
assert.deepEqual(parseAndEval('"line end\\nnext"'), 'line end\nnext');
assert.deepEqual(parseAndEval('"line end\\n"'), 'line end\n');
assert.deepEqual(parseAndEval('"tab\\tnext"'), 'tab\tnext');
assert.deepEqual(parseAndEval('"tab\\t"'), 'tab\t');
assert.deepEqual(parseAndEval('"escaped backslash\\\\next"'), 'escaped backslash\\next');
assert.deepEqual(parseAndEval('"escaped backslash\\\\"'), 'escaped backslash\\');
});
it('should throw an error with invalid strings', function() {
assert.throws(function () {parseAndEval('"hi'); }, SyntaxError);
assert.throws(function () {parseAndEval(' hi" '); }, Error);
});
it('should get a string subset', function() {
var scope = {};
assert.deepEqual(parseAndEval('c="hello"', scope), "hello");
assert.deepEqual(parseAndEval('c[2:4]', scope), "ell");
assert.deepEqual(parseAndEval('c[5:-1:1]', scope), "olleh");
assert.deepEqual(parseAndEval('c[end-2:-1:1]', scope), "leh");
assert.deepEqual(parseAndEval('"hello"[2:4]', scope), "ell");
});
it('should set a string subset', function() {
var scope = {};
assert.deepEqual(parseAndEval('c="hello"', scope), "hello");
assert.deepEqual(parseAndEval('c[1] = "H"', scope), "H");
assert.deepEqual(scope.c, "Hello");
assert.deepEqual(parseAndEval('c', scope), "Hello");
assert.deepEqual(parseAndEval('c[6:11] = " world"', scope), " world");
assert.deepEqual(scope.c, "Hello world");
assert.deepEqual(parseAndEval('c[end] = "D"', scope), "D");
assert.deepEqual(scope.c, "Hello worlD");
});
it('should set a string subset on an object', function() {
var scope = { a: {} };
assert.deepEqual(parseAndEval('a.c="hello"', scope), "hello");
assert.deepEqual(parseAndEval('a.c[1] = "H"', scope), "H");
assert.deepEqual(scope.a, {c: "Hello"});
assert.deepEqual(parseAndEval('a.c', scope), "Hello");
assert.deepEqual(parseAndEval('a.c[6:11] = " world"', scope), " world");
assert.deepEqual(scope.a, {c: "Hello world"});
assert.deepEqual(parseAndEval('a.c', scope), "Hello world");
assert.deepEqual(scope.a, {c: "Hello world"});
assert.deepEqual(parseAndEval('a.c[end] = "D"', scope), "D");
assert.deepEqual(scope.a, {c: "Hello worlD"});
});
});
describe('unit', function () {
it('should parse units', function() {
assert.deepEqual(parseAndEval('5cm'), new Unit(5, 'cm'));
assert.ok(parseAndEval('5cm') instanceof Unit);
});
it('should correctly parse negative temperatures', function () {
approx.deepEqual(parseAndEval('-6 celsius'), new Unit(-6, 'celsius'));
approx.deepEqual(parseAndEval('--6 celsius'), new Unit(6, 'celsius'));
approx.deepEqual(parseAndEval('-6 celsius to fahrenheit'),
new Unit(21.2, 'fahrenheit').to('fahrenheit'));
});
it('should convert units', function() {
var scope = {};
approx.deepEqual(parseAndEval('(5.08 cm * 1000) to inch', scope),
math.unit(2000, 'inch').to('inch'));
approx.deepEqual(parseAndEval('a = (5.08 cm * 1000) to mm', scope),
math.unit(50800, 'mm').to('mm'));
approx.deepEqual(parseAndEval('a to inch', scope),
math.unit(2000, 'inch').to('inch'));
approx.deepEqual(parseAndEval('10 celsius to fahrenheit'),
math.unit(50, 'fahrenheit').to('fahrenheit'));
approx.deepEqual(parseAndEval('20 celsius to fahrenheit'),
math.unit(68, 'fahrenheit').to('fahrenheit'));
approx.deepEqual(parseAndEval('50 fahrenheit to celsius'),
math.unit(10, 'celsius').to('celsius'));
});
it('should evaluate operator "to" with correct precedence ', function () {
approx.deepEqual(parseAndEval('5.08 cm * 1000 to inch'),
new Unit(2000, 'inch').to('inch'));
});
it('should evaluate operator "in" (alias of "to") ', function () {
approx.deepEqual(parseAndEval('5.08 cm in inch'),
new Unit(2, 'inch').to('inch'));
});
it('should evaluate unit "in" (should not conflict with operator "in")', function () {
approx.deepEqual(parseAndEval('2 in'), new Unit(2, 'in'));
approx.deepEqual(parseAndEval('5.08 cm in in'), new Unit(2, 'in').to('in'));
approx.deepEqual(parseAndEval('5 in in in'), new Unit(5, 'in').to('in'));
approx.deepEqual(parseAndEval('2 in to meter'), new Unit(2, 'inch').to('meter'));
approx.deepEqual(parseAndEval('2 in in meter'), new Unit(2, 'inch').to('meter'));
approx.deepEqual(parseAndEval('a in inch', {a: new Unit(5.08, 'cm')}), new Unit(2, 'inch').to('inch'));
approx.deepEqual(parseAndEval('(2+3) in'), new Unit(5, 'in'));
approx.deepEqual(parseAndEval('a in', {a: 5}), new Unit(5, 'in'));
approx.deepEqual(parseAndEval('0.5in + 1.5in to cm'), new Unit(5.08, 'cm').to('cm'));
});
});
describe('complex', function () {
it('should parse complex values', function () {
assert.deepEqual(parseAndEval('i'), new Complex(0,1));
assert.deepEqual(parseAndEval('2+3i'), new Complex(2,3));
assert.deepEqual(parseAndEval('2+3*i'), new Complex(2,3));
assert.deepEqual(parseAndEval('1/2i'), new Complex(0, 0.5));
});
});
describe('matrix', function () {
it('should parse a matrix', function() {
assert.ok(parseAndEval('[1,2;3,4]') instanceof Matrix);
var m = parseAndEval('[1,2,3;4,5,6]');
assert.deepEqual(m.size(), [2,3]);
assert.deepEqual(m, math.matrix([[1,2,3],[4,5,6]]));
var b = parseAndEval('[5, 6; 1, 1]');
assert.deepEqual(b.size(), [2,2]);
assert.deepEqual(b, math.matrix([[5,6],[1,1]]));
// from 1 to n dimensions
assert.deepEqual(parseAndEval('[ ]'), math.matrix([]));
assert.deepEqual(parseAndEval('[1,2,3]'), math.matrix([1,2,3]));
assert.deepEqual(parseAndEval('[1;2;3]'), math.matrix([[1],[2],[3]]));
assert.deepEqual(parseAndEval('[[1,2],[3,4]]'), math.matrix([[1,2],[3,4]]));
assert.deepEqual(parseAndEval('[[[1],[2]],[[3],[4]]]'), math.matrix([[[1],[2]],[[3],[4]]]));
});
it('should parse an empty matrix', function() {
assert.deepEqual(parseAndEval('[]'), math.matrix([]));
});
it('should get a matrix subset', function() {
var scope = {
a: math.matrix([
[1,2,3],
[4,5,6],
[7,8,9]
])
};
assert.deepEqual(parseAndEval('a[2, :]', scope), math.matrix([[4,5,6]]));
assert.deepEqual(parseAndEval('a[2, :2]', scope), math.matrix([[4,5]]));
assert.deepEqual(parseAndEval('a[2, :end-1]', scope), math.matrix([[4,5]]));
assert.deepEqual(parseAndEval('a[2, 2:]', scope), math.matrix([[5,6]]));
assert.deepEqual(parseAndEval('a[2, 2:3]', scope), math.matrix([[5,6]]));
assert.deepEqual(parseAndEval('a[2, 1:2:3]', scope), math.matrix([[4,6]]));
assert.deepEqual(parseAndEval('a[:, 2]', scope), math.matrix([[2],[5],[8]]));
assert.deepEqual(parseAndEval('a[:2, 2]', scope), math.matrix([[2],[5]]));
assert.deepEqual(parseAndEval('a[:end-1, 2]', scope), math.matrix([[2],[5]]));
assert.deepEqual(parseAndEval('a[2:, 2]', scope), math.matrix([[5],[8]]));
assert.deepEqual(parseAndEval('a[2:3, 2]', scope), math.matrix([[5],[8]]));
assert.deepEqual(parseAndEval('a[1:2:3, 2]', scope), math.matrix([[2],[8]]));
});
it('should get a matrix subset of a matrix subset', function() {
var scope = {
a: math.matrix([
[1,2,3],
[4,5,6],
[7,8,9]
])
};
assert.deepEqual(parseAndEval('a[2, :][1,1]', scope), 4);
});
it('should parse matrix resizings', function() {
var scope = {};
assert.deepEqual(parseAndEval('a = []', scope), math.matrix([]));
assert.deepEqual(parseAndEval('a[1:3,1] = [1;2;3]', scope), math.matrix([[1],[2],[3]]));
assert.deepEqual(parseAndEval('a[:,2] = [4;5;6]', scope), math.matrix([[4],[5],[6]]));
assert.deepEqual(scope.a, math.matrix([[1,4],[2,5],[3,6]]));
assert.deepEqual(parseAndEval('a = []', scope), math.matrix([]));
assert.strictEqual(parseAndEval('a[1,3] = 3', scope), 3);
assert.deepEqual(scope.a, math.matrix([[0,0,3]]));
assert.deepEqual(parseAndEval('a[2,:] = [[4,5,6]]', scope), math.matrix([[4,5,6]]));
assert.deepEqual(scope.a, math.matrix([[0,0,3],[4,5,6]]));
assert.deepEqual(parseAndEval('a = []', scope), math.matrix([]));
assert.strictEqual(parseAndEval('a[3,1] = 3', scope), 3);
assert.deepEqual(scope.a, math.matrix([[0],[0],[3]]));
assert.deepEqual(parseAndEval('a[:,2] = [4;5;6]', scope), math.matrix([[4],[5],[6]]));
assert.deepEqual(scope.a, math.matrix([[0,4],[0,5],[3,6]]));
assert.deepEqual(parseAndEval('a = []', scope), math.matrix([]));
assert.deepEqual(parseAndEval('a[1,1:3] = [[1,2,3]]', scope), math.matrix([[1,2,3]]));
assert.deepEqual(scope.a, math.matrix([[1,2,3]]));
assert.deepEqual(parseAndEval('a[2,:] = [[4,5,6]]', scope), math.matrix([[4,5,6]]));
assert.deepEqual(scope.a, math.matrix([[1,2,3],[4,5,6]]));
});
it('should get/set the matrix correctly', function() {
var scope = {};
parseAndEval('a=[1,2;3,4]', scope);
parseAndEval('a[1,1] = 100', scope);
assert.deepEqual(scope.a.size(), [2,2]);
assert.deepEqual(scope.a, math.matrix([[100,2],[3,4]]));
parseAndEval('a[2:3,2:3] = [10,11;12,13]', scope);
assert.deepEqual(scope.a.size(), [3,3]);
assert.deepEqual(scope.a, math.matrix([[100, 2, 0],[3,10,11],[0,12,13]]));
var a = scope.a;
// note: after getting subset, uninitialized elements are replaced by elements with an undefined value
assert.deepEqual(a.subset(math.index(new Range(0,3), new Range(0,2))), math.matrix([[100,2],[3,10],[0,12]]));
assert.deepEqual(parseAndEval('a[1:3,1:2]', scope), math.matrix([[100,2],[3,10],[0,12]]));
scope.b = [[1,2],[3,4]];
assert.deepEqual(parseAndEval('b[1,:]', scope), [[1, 2]]);
});
it('should get/set the matrix correctly for 3d matrices', function() {
var scope = {};
assert.deepEqual(parseAndEval('f=[1,2;3,4]', scope), math.matrix([[1,2],[3,4]]));
assert.deepEqual(parseAndEval('size(f)', scope), math.matrix([2,2]));
parseAndEval('f[:,:,2]=[5,6;7,8]', scope);
assert.deepEqual(scope.f, math.matrix([
[
[1,5],
[2,6]
],
[
[3,7],
[4,8]
]
]));
assert.deepEqual(parseAndEval('size(f)', scope), math.matrix([2,2,2]));
assert.deepEqual(parseAndEval('f[:,:,1]', scope), math.matrix([[[1],[2]],[[3],[4]]]));
assert.deepEqual(parseAndEval('f[:,:,2]', scope), math.matrix([[[5],[6]],[[7],[8]]]));
assert.deepEqual(parseAndEval('f[:,2,:]', scope), math.matrix([[[2,6]],[[4,8]]]));
assert.deepEqual(parseAndEval('f[2,:,:]', scope), math.matrix([[[3,7],[4,8]]]));
parseAndEval('a=diag([1,2,3,4])', scope);
assert.deepEqual(parseAndEval('a[3:end, 3:end]', scope), math.matrix([[3,0],[0,4]]));
parseAndEval('a[3:end, 2:end]=9*ones(2,3)', scope);
assert.deepEqual(scope.a, math.matrix([
[1,0,0,0],
[0,2,0,0],
[0,9,9,9],
[0,9,9,9]
]));
assert.deepEqual(parseAndEval('a[2:end-1, 2:end-1]', scope), math.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=concat(a,b)', scope), math.matrix([[1,2,5,6],[3,4,7,8]]));
assert.deepEqual(parseAndEval('c=concat(a,b,1)', scope), math.matrix([[1,2],[3,4],[5,6],[7,8]]));
assert.deepEqual(parseAndEval('c=concat(concat(a,b), concat(b,a), 1)', scope), math.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]], 1)', scope), math.matrix([[1,2],[3,4]]));
assert.deepEqual(parseAndEval('c=concat([[1,2]], [[3,4]], 2)', scope), math.matrix([[1,2,3,4]]));
assert.deepEqual(parseAndEval('c=concat([[1]], [2;3], 1)', scope), math.matrix([[1],[2],[3]]));
assert.deepEqual(parseAndEval('d=1:3', scope), math.matrix([1,2,3]));
assert.deepEqual(parseAndEval('concat(d,d)', scope), math.matrix([1,2,3,1,2,3]));
assert.deepEqual(parseAndEval('e=1+d', scope), math.matrix([2,3,4]));
assert.deepEqual(parseAndEval('size(e)', scope), math.matrix([3]));
assert.deepEqual(parseAndEval('concat(e,e)', scope), math.matrix([2,3,4,2,3,4]));
assert.deepEqual(parseAndEval('[[],[]]', scope), math.matrix([[],[]]));
assert.deepEqual(parseAndEval('[[],[]]', scope).size(), [2, 0]);
assert.deepEqual(parseAndEval('size([[],[]])', scope), math.matrix([2, 0]));
});
it('should execute map on an array with one based indices', function () {
var logs = [];
var scope = {
A: [1,2,3],
callback: function (value, index, matrix) {
assert.strictEqual(matrix, scope.A);
// note: we don't copy index, index should be a new Array for every call of callback
logs.push([value, index]);
return value + 1;
}
};
var res = math.eval('map(A, callback)', scope);
assert.deepEqual(res, [2,3,4]);
assert.deepEqual(logs, [[1, [1]], [2, [2]], [3, [3]]]);
});
it('should execute map on a Matrix with one based indices', function () {
var logs = [];
var scope = {
A: math.matrix([1,2,3]),
callback: function (value, index, matrix) {
assert.strictEqual(matrix, scope.A);
// note: we don't copy index, index should be a new Array for every call of callback
logs.push([value, index]);
return value + 1;
}
};
var res = math.eval('map(A, callback)', scope);
assert.deepEqual(res, math.matrix([2,3,4]));
assert.deepEqual(logs, [[1, [1]], [2, [2]], [3, [3]]]);
});
it('should execute forEach on an array with one based indices', function () {
var logs = [];
var scope = {
A: [1,2,3],
callback: function (value, index, matrix) {
assert.strictEqual(matrix, scope.A);
// note: we don't copy index, index should be a new Array for every call of callback
logs.push([value, index]);
}
};
math.eval('forEach(A, callback)', scope);
assert.deepEqual(logs, [[1, [1]], [2, [2]], [3, [3]]]);
});
it('should execute forEach on a Matrix with one based indices', function () {
var logs = [];
var scope = {
A: math.matrix([1,2,3]),
callback: function (value, index, matrix) {
assert.strictEqual(matrix, scope.A);
// note: we don't copy index, index should be a new Array for every call of callback
logs.push([value, index]);
}
};
math.eval('forEach(A, callback)', scope);
assert.deepEqual(logs, [[1, [1]], [2, [2]], [3, [3]]]);
});
it('should disable arrays as range in a matrix index', function () {
var scope = {
a: [[1,2,3],[4,5,6]]
};
assert.throws(function () {
parseAndEval('a[2, 2+3i]', scope);
}, /TypeError: Dimension must be an Array, Matrix, number, string, or Range/);
});
it('should throw an error for invalid matrix', function() {
assert.throws(function () {parseAndEval('[1, 2');}, /End of matrix ] expected/);
assert.throws(function () {parseAndEval('[1; 2');}, /End of matrix ] expected/);
});
it('should throw an error when matrix rows mismatch', function() {
assert.throws(function () {parseAndEval('[1, 2; 1, 2, 3]');}, /Column dimensions mismatch/);
});
it('should throw an error for invalid matrix subsets', function() {
var scope = {a: [1,2,3]};
assert.throws(function () {parseAndEval('a[1', scope);}, /Parenthesis ] expected/);
});
it('should throw an error for invalid matrix concatenations', function() {
var scope = {};
assert.throws(function () {parseAndEval('c=concat(a, [1,2,3])', scope);});
});
});
describe('objects', function () {
it('should get an object property', function () {
assert.deepEqual(parseAndEval('obj["foo"]', {obj: {foo: 2}}), 2);
});
it('should get a nested object property', function () {
assert.deepEqual(parseAndEval('obj["foo"]["bar"]', {obj: {foo: {bar: 2}}}), 2);
});
it('should get a nested matrix subset from an object property', function () {
assert.deepEqual(parseAndEval('obj.foo[2]', {obj: {foo: [1,2,3]}}), 2);
assert.deepEqual(parseAndEval('obj.foo[end]', {obj: {foo: [1,2,3]}}), 3);
assert.deepEqual(parseAndEval('obj.foo[2][3]', {obj: {foo: ['hello', 'world']}}), 'r');
assert.deepEqual(parseAndEval('obj.foo[2][end]', {obj: {foo: ['hello', 'world']}}), 'd');
assert.deepEqual(parseAndEval('obj.foo[1].bar', {obj: {foo: [{bar:4}]}}), 4);
});
it('should set an object property', function () {
var scope = {obj: {a:3}};
var res = parseAndEval('obj["b"] = 2', scope);
assert.strictEqual(res, 2);
assert.deepEqual(scope, {obj: {a: 3, b: 2}});
});
it('should set a nested object property', function () {
var scope = {obj: {foo: {}}};
var res = parseAndEval('obj["foo"]["bar"] = 2', scope);
assert.strictEqual(res, 2);
assert.deepEqual(scope, {obj: {foo: {bar: 2}}});
});
it('should throw an error when trying to apply a matrix index as object property', function () {
var scope = {a: {}};
assert.throws(function () {
parseAndEval('a[2] = 6', scope);
}, /Cannot apply a numeric index as object property/);
});
it('should set a nested matrix subset from an object property (1)', function () {
var scope = {obj: {foo: [1,2,3]}};
assert.deepEqual(parseAndEval('obj.foo[2] = 6', scope), 6);
assert.deepEqual(scope, {obj: {foo: [1,6,3]}});
assert.deepEqual(parseAndEval('obj.foo[end] = 8', scope), 8);
assert.deepEqual(scope, {obj: {foo: [1,6,8]}});
});
it('should set a nested matrix subset from an object property (2)', function () {
var scope = {obj: {foo: [{bar:4}]}};
assert.deepEqual(parseAndEval('obj.foo[1].bar = 6', scope), 6);
assert.deepEqual(scope, {obj: {foo: [{bar: 6}]}});
});
it('should set a nested matrix subset from an object property (3)', function () {
var scope = {obj: {foo: [{bar:{}}]}};
assert.deepEqual(parseAndEval('obj.foo[1].bar.baz = 6', scope), 6);
assert.deepEqual(scope, {obj: {foo: [{bar: {baz:6}}]}});
});
it('should set a nested matrix subset from an object property (4)', function () {
var scope = {obj: {foo: ['hello', 'world']}};
assert.deepEqual(parseAndEval('obj.foo[1][end] = "a"', scope), 'a');
assert.deepEqual(scope, {obj: {foo: ['hella', 'world']}});
assert.deepEqual(parseAndEval('obj.foo[end][end] = "!"', scope), '!');
assert.deepEqual(scope, {obj: {foo: ['hella', 'worl!']}});
});
// TODO: test whether 1-based IndexErrors are thrown
it('should get an object property with dot notation', function () {
assert.deepEqual(parseAndEval('obj.foo', {obj: {foo: 2}}), 2);
});
it('should get an object property from an object inside parentheses', function () {
assert.deepEqual(parseAndEval('(obj).foo', {obj: {foo: 2}}), 2);
});
it('should get a nested object property with dot notation', function () {
assert.deepEqual(parseAndEval('obj.foo.bar', {obj: {foo: {bar: 2}}}), 2);
});
it('should invoke a function in an object', function () {
var scope = {
obj: {
fn: function (x) {
return x * x;
}
}
};
assert.deepEqual(parseAndEval('obj.fn(2)', scope), 4);
assert.deepEqual(parseAndEval('obj["fn"](2)', scope), 4);
});
it('should invoke a function returned by a function', function () {
var scope = {
theAnswer: function () {
return function () {
return 42;
};
},
partialAdd: function (a) {
return function (b) {
return a + b;
};
}
};
assert.deepEqual(parseAndEval('theAnswer()()', scope), 42);
assert.deepEqual(parseAndEval('partialAdd(2)(3)', scope), 5);
});
it('should invoke a function which is a property of a function', function () {
function f () {
return '42'
}
f.foo = function () {
return 'bar'
}
assert.deepEqual(parseAndEval('f.foo()', {f: f}), 'bar');
});
it('should invoke a function on an object with the right context', function () {
approx.equal(parseAndEval('(2.54 cm).toNumeric("inch")'), 1);
assert.deepEqual(parseAndEval('bignumber(2).plus(3)'), math.bignumber(5));
assert.deepEqual(parseAndEval('bignumber(2)["plus"](3)'), math.bignumber(5));
});
it('should invoke toString on some object', function () {
assert.strictEqual(parseAndEval('(3).toString()'), '3');
});
it('should get nested object property with mixed dot- and index-notation', function () {
assert.deepEqual(parseAndEval('obj.foo["bar"].baz', {obj: {foo: {bar: {baz: 2}}}}), 2);
assert.deepEqual(parseAndEval('obj["foo"].bar["baz"]', {obj: {foo: {bar: {baz: 2}}}}), 2);
});
it('should set an object property with dot notation', function () {
var scope = {obj: {}};
parseAndEval('obj.foo = 2', scope);
assert.deepEqual(scope, {obj: {foo: 2}});
});
it('should set a nested object property with dot notation', function () {
var scope = {obj: {foo: {}}};
parseAndEval('obj.foo.bar = 2', scope);
assert.deepEqual(scope, {obj: {foo: {bar: 2}}});
});
it('should throw an error in case of invalid property with dot notation', function () {
assert.throws(function () {parseAndEval('obj. +foo')}, /SyntaxError: Property name expected after dot \(char 6\)/);
assert.throws(function () {parseAndEval('obj.["foo"]')}, /SyntaxError: Property name expected after dot \(char 5\)/);
});
it('should create an empty object', function () {
assert.deepEqual(parseAndEval('{}'), {});
});
it('should create an object with quoted keys', function () {
assert.deepEqual(parseAndEval('{"a":2+3,"b":"foo"}'), {a: 5, b: 'foo'});
});
it('should create an object with unquoted keys', function () {
assert.deepEqual(parseAndEval('{a:2+3,b:"foo"}'), {a: 5, b: 'foo'});
});
it('should create an object with child object', function () {
assert.deepEqual(parseAndEval('{a:{b:2}}'), {a:{b:2}})
});
it('should get a property from a just created object', function () {
assert.deepEqual(parseAndEval('{foo:2}["foo"]'), 2);
});
it('should parse an object containing a function assignment', function () {
var obj = parseAndEval('{f: f(x)=x^2}');
assert.deepEqual(Object.keys(obj), ['f']);
assert.equal(obj.f(2), 4);
});
it('should parse an object containing a variable assignment', function () {
var scope = {};
assert.deepEqual(parseAndEval('{f: a=42}', scope), {f: 42});
assert.strictEqual(scope.a, 42);
});
it('should throw an exception in case of invalid object key', function () {
assert.throws(function () {parseAndEval('{a b: 2}')}, /SyntaxError: Colon : expected after object key \(char 4\)/);
assert.throws(function () {parseAndEval('{a: }')}, /SyntaxError: Value expected \(char 5\)/);
});
});
describe('boolean', function () {
it('should parse boolean values', function () {
assert.equal(parseAndEval('true'), true);
assert.equal(parseAndEval('false'), false);
});
});
describe('constants', function () {
it('should parse constants', function() {
assert.deepEqual(parseAndEval('i'), new Complex(0, 1));
approx.equal(parseAndEval('pi'), Math.PI);
approx.equal(parseAndEval('e'), Math.E);
});
});
describe('variables', function () {
it('should parse valid variable assignments', function() {
var scope = {};
assert.equal(parseAndEval('a = 0.75', scope), 0.75);
assert.equal(parseAndEval('a + 2', scope), 2.75);
assert.equal(parseAndEval('a = 2', scope), 2);
assert.equal(parseAndEval('a + 2', scope), 4);
approx.equal(parseAndEval('pi * 2', scope), 6.283185307179586);
});
it('should throw an error on undefined symbol', function() {
assert.throws(function() {parseAndEval('qqq + 2'); });
});
it('should throw an error on invalid assignments', function() {
//assert.throws(function () {parseAndEval('sin(2) = 0.75')}, SyntaxError); // TODO: should this throw an exception?
assert.throws(function () {parseAndEval('sin + 2 = 3');}, SyntaxError);
});
it('should parse nested assignments', function() {
var scope = [];
assert.equal(parseAndEval('c = d = (e = 4.5)', scope), 4.5);
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), math.matrix([1,2,3]));
assert.equal(scope.f, 3);
assert.equal(parseAndEval('2 + (g = 3 + 4)', scope), 9);
assert.equal(scope.g, 7);
});
it('should parse variable assignment inside a function call', function() {
var scope = {};
assert.deepEqual(parseAndEval('sqrt(x=4)', scope), 2);
assert.deepEqual(scope, { x:4 });
});
it('should parse variable assignment inside an accessor', function () {
var scope = {A: [10,20,30]};
assert.deepEqual(parseAndEval('A[x=2]', scope), 20);
assert.deepEqual(scope, { A:[10,20,30], x:2 });
});
});
describe('functions', function () {
it('should parse functions', function() {
assert.equal(parseAndEval('sqrt(4)'), 2);
assert.equal(parseAndEval('sqrt(6+3)'), 3);
assert.equal(parseAndEval('atan2(2,2)'), 0.7853981633974483);
assert.deepEqual(parseAndEval('sqrt(-4)'), new Complex(0, 2));
assert.equal(parseAndEval('abs(-4.2)'), 4.2);
assert.equal(parseAndEval('add(2, 3)'), 5);
approx.deepEqual(parseAndEval('1+exp(pi*i)'), new Complex(0, 0));
assert.equal(parseAndEval('unequal(2, 3)'), true);
});
it('should get a subset of a matrix returned by a function', function() {
var scope = {
test: function () {
return [1,2,3,4];
}
};
assert.equal(parseAndEval('test()[2]', scope), 2);
});
it('should parse functions without parameters', function() {
assert.equal(parseAndEval('r()', {r: function() {return 2;}}), 2);
});
it('should parse function assignments', function() {
var scope = {};
parseAndEval('x=100', scope); // for testing scoping of the function variables
assert.equal(parseAndEval('f(x) = x^2', scope).syntax, 'f(x)');
assert.equal(parseAndEval('f(3)', scope), 9);
assert.equal(scope.f(3), 9);
assert.equal(scope.x, 100);
assert.equal(parseAndEval('g(x, y) = x^y', scope).syntax, 'g(x, y)');
assert.equal(parseAndEval('g(4,5)', scope), 1024);
assert.equal(scope.g(4,5), 1024);
});
it ('should correctly evaluate variables in assigned functions', function () {
var scope = {};
assert.equal(parseAndEval('a = 3', scope), 3);
assert.equal(parseAndEval('f(x) = a * x', scope).syntax, 'f(x)');
assert.equal(parseAndEval('f(2)', scope), 6);
assert.equal(parseAndEval('a = 5', scope), 5);
assert.equal(parseAndEval('f(2)', scope), 10);
assert.equal(parseAndEval('g(x) = x^q', scope).syntax, 'g(x)');
assert.equal(parseAndEval('q = 4/2', scope), 2);
assert.equal(parseAndEval('g(3)', scope), 9);
});
it('should throw an error for undefined variables in an assigned function', function() {
var scope = {};
assert.equal(parseAndEval('g(x) = x^q', scope).syntax, 'g(x)');
assert.throws(function () {
parseAndEval('g(3)', scope);
}, function (err) {
return (err instanceof Error) && (err.toString() == 'Error: Undefined symbol q');
});
});
it('should throw an error on invalid left hand side of a function assignment', function() {
assert.throws(function () {
var scope = {};
parseAndEval('g(x, 2) = x^2', scope);
}, SyntaxError);
assert.throws(function () {
var scope = {};
parseAndEval('2(x, 2) = x^2', scope);
}, SyntaxError);
});
});
describe ('parentheses', function () {
it('should parse parentheses overriding the default precedence', function () {
approx.equal(parseAndEval('2 - (2 - 2)'), 2);
approx.equal(parseAndEval('2 - ((2 - 2) - 2)'), 4);
approx.equal(parseAndEval('3 * (2 + 3)'), 15);
approx.equal(parseAndEval('(2 + 3) * 3'), 15);
});
it('should throw an error in case of unclosed parentheses', function () {
assert.throws(function () {parseAndEval('3 * (1 + 2');}, /Parenthesis \) expected/);
});
});
describe ('operators', function () {
it('should parse operations', function() {
approx.equal(parseAndEval('(2+3)/4'), 1.25);
approx.equal(parseAndEval('2+3/4'), 2.75);
assert.equal(parse('0 + 2').toString(), '0 + 2');
});
it('should parse add +', function() {
assert.equal(parseAndEval('2 + 3'), 5);
assert.equal(parseAndEval('2 + 3 + 4'), 9);
assert.equal(parseAndEval('2.+3'), 5); // test whether the decimal mark isn't confused
});
it('should parse divide /', function() {
assert.equal(parseAndEval('4 / 2'), 2);
assert.equal(parseAndEval('8 / 2 / 2'), 2);
});
it('should parse dotDivide ./', function() {
assert.equal(parseAndEval('4./2'), 2);
assert.deepEqual(parseAndEval('4./[2,4]'), math.matrix([2,1]));
assert.equal(parseAndEval('4 ./ 2'), 2);
assert.equal(parseAndEval('8 ./ 2 / 2'), 2);
assert.deepEqual(parseAndEval('[1,2,3] ./ [1,2,3]'), math.matrix([1,1,1]));
});
it('should parse dotMultiply .*', function() {
approx.deepEqual(parseAndEval('2.*3'), 6);
approx.deepEqual(parseAndEval('2e3.*3'), 6e3);
approx.deepEqual(parseAndEval('2 .* 3'), 6);
approx.deepEqual(parseAndEval('4 .* 2'), 8);
approx.deepEqual(parseAndEval('8 .* 2 .* 2'), 32);
assert.deepEqual(parseAndEval('a=3; a.*4'), new ResultSet([12]));
assert.deepEqual(parseAndEval('[1,2,3] .* [1,2,3]'), math.matrix([1,4,9]));
});
it('should parse dotPower .^', function() {
approx.deepEqual(parseAndEval('2.^3'), 8);
approx.deepEqual(parseAndEval('2 .^ 3'), 8);
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]'), math.matrix([4,27]));
});
it('should parse equal ==', function() {
assert.strictEqual(parseAndEval('2 == 3'), false);
assert.strictEqual(parseAndEval('2 == 2'), true);
assert.deepEqual(parseAndEval('[2,3] == [2,4]'), math.matrix([true, false]));
});
it('should parse larger >', function() {
assert.equal(parseAndEval('2 > 3'), false);
assert.equal(parseAndEval('2 > 2'), false);
assert.equal(parseAndEval('2 > 1'), true);
});
it('should parse largerEq >=', function() {
assert.equal(parseAndEval('2 >= 3'), false);
assert.equal(parseAndEval('2 >= 2'), true);
assert.equal(parseAndEval('2 >= 1'), true);
});
it('should parse mod %', function() {
approx.equal(parseAndEval('8 % 3'), 2);
});
it('should parse operator mod', function() {
approx.equal(parseAndEval('8 mod 3'), 2);
});
it('should parse multiply *', function() {
approx.equal(parseAndEval('4 * 2'), 8);
approx.equal(parseAndEval('8 * 2 * 2'), 32);
});
it('should parse implicit multiplication', function() {
assert.equal(parseAndEval('4a', {a:2}), 8);
assert.equal(parseAndEval('4 a', {a:2}), 8);
assert.equal(parseAndEval('a b', {a: 2, b: 4}), 8);
assert.equal(parseAndEval('2a b', {a: 2, b: 4}), 16);
assert.equal(parseAndEval('2a * b', {a: 2, b: 4}), 16);
assert.equal(parseAndEval('2a / b', {a: 2, b: 4}), 1);
assert.equal(parseAndEval('a b c', {a: 2, b: 4, c: 6}), 48);
assert.equal(parseAndEval('a b*c', {a: 2, b: 4, c: 6}), 48);
assert.equal(parseAndEval('a*b c', {a: 2, b: 4, c: 6}), 48);
assert.equal(parseAndEval('a/b c', {a: 4, b: 2, c: 6}), 12);
assert.equal(parseAndEval('1/2a', {a:2}), 1);
assert.equal(parseAndEval('8/2a/2', {a:2}), 4);
assert.equal(parseAndEval('8/2a*2', {a:2}), 16);
assert.equal(parseAndEval('4*2a', {a:2}), 16);
assert.equal(parseAndEval('3!10'), 60);
assert.equal(parseAndEval('(2+3)a', {a:2}), 10);
assert.equal(parseAndEval('(2+3)2'), 10);
assert.equal(parseAndEval('(2)(3)+4'), 10);
assert.equal(parseAndEval('2(3+4)'), 14);
assert.equal(parseAndEval('(2+3)-2'), 3); // no implicit multiplication, just a unary minus
assert.equal(parseAndEval('a(2+3)', {a: function() {return 42;}}), 42); // function call
assert.equal(parseAndEval('a.b(2+3)', {a: {b: function() {return 42;}}}), 42); // function call
assert.equal(parseAndEval('(2+3)(4+5)'), 45); // implicit multiplication
assert.equal(parseAndEval('(2+3)(4+5)(3-1)'), 90); // implicit multiplication
assert.equal(parseAndEval('(2a)^3', {a:2}), 64);
assert.equal(parseAndEval('2a^3', {a:2}), 16);
assert.equal(parseAndEval('2(a)^3', {a:2}), 16);
assert.equal(parseAndEval('(2)a^3', {a:2}), 16);
assert.equal(parseAndEval('2^3a', {a:2}), 16);
assert.equal(parseAndEval('2^3(a)', {a:2}), 16);
assert.equal(parseAndEval('2^(3)(a)', {a:2}), 16);
assert.equal(parseAndEval('sqrt(2a)', {a:2}), 2);
assert.deepEqual(parseAndEval('[2, 3] 2'), math.matrix([4, 6]));
assert.deepEqual(parseAndEval('[2, 3] a', {a:2}), math.matrix([4, 6]));
assert.deepEqual(parseAndEval('A [2,2]', {A: [[1,2], [3,4]]}), 4); // index
assert.deepEqual(parseAndEval('(A) [2,2]', {A: [[1,2], [3,4]]}), 4); // index
assert.deepEqual(parseAndEval('[1,2;3,4] [2,2]'), 4); // index
assert.deepEqual(parseAndEval('([1,2;3,4])[2,2]'), 4); // index
assert.throws(function () {parseAndEval('2[1,2,3]')}, /Unexpected operator/);// index
});
it('should tell the OperatorNode about implicit multiplications', function() {
assert.equal(parse('2 + 3').implicit, false);
assert.equal(parse('4 * a').implicit, false);
assert.equal(parse('4a').implicit, true);
assert.equal(parse('4 a').implicit, true);
assert.equal(parse('a b').implicit, true);
assert.equal(parse('2a b').implicit, true);
assert.equal(parse('a b c').implicit, true);
assert.equal(parse('(2+3)a').implicit, true);
assert.equal(parse('(2+3)2').implicit, true);
assert.equal(parse('2(3+4)').implicit, true);
});
it('should correctly order consecutive multiplications and implicit multiplications', function() {
var node = parse('9km*3km');
assert.equal(node.toString({parenthesis: 'all'}), '((9 km) * 3) km');
});
it('should throw an error when having an implicit multiplication between two numbers', function() {
assert.throws(function () { math.parse('2 3'); }, /Unexpected part "3"/);
assert.throws(function () { math.parse('2 * 3 4'); }, /Unexpected part "4"/);
assert.throws(function () { math.parse('2 * 3 4 * 5'); }, /Unexpected part "4"/);
assert.throws(function () { math.parse('2 / 3 4 5'); }, /Unexpected part "4"/);
assert.throws(function () { math.parse('2 + 3 4'); }, /Unexpected part "4"/);
assert.throws(function () { math.parse('-2 2'); }, /Unexpected part "2"/);
assert.throws(function () { math.parse('+3 3'); }, /Unexpected part "3"/);
assert.throws(function () { math.parse('2^3 4'); }, /Unexpected part "4"/);
});
it('should parse pow ^', function() {
approx.equal(parseAndEval('2^3'), 8);
approx.equal(parseAndEval('-2^2'), -4); // -(2^2)
approx.equal(parseAndEval('2^3^4'), 2.41785163922926e+24); // 2^(3^4)
});
it('should parse smaller <', function() {
assert.strictEqual(parseAndEval('2 < 3'), true);
assert.strictEqual(parseAndEval('2 < 2'), false);
assert.strictEqual(parseAndEval('2 < 1'), false);
});
it('should parse smallerEq <=', function() {
assert.strictEqual(parseAndEval('2 <= 3'), true);
assert.strictEqual(parseAndEval('2 <= 2'), true);
assert.strictEqual(parseAndEval('2 <= 1'), false);
});
it('should parse bitwise and &', function() {
assert.strictEqual(parseAndEval('2 & 6'), 2);
assert.strictEqual(parseAndEval('5 & 3'), 1);
assert.strictEqual(parseAndEval('true & true'), 1);
assert.strictEqual(parseAndEval('true & false'), 0);
assert.strictEqual(parseAndEval('false & true'), 0);
assert.strictEqual(parseAndEval('false & false'), 0);
});
it('should parse bitwise xor ^|', function() {
assert.strictEqual(parseAndEval('2 ^| 6'), 4);
assert.strictEqual(parseAndEval('5 ^| 3'), 6);
assert.strictEqual(parseAndEval('true ^| true'), 0);
assert.strictEqual(parseAndEval('true ^| false'), 1);
assert.strictEqual(parseAndEval('false ^| true'), 1);
assert.strictEqual(parseAndEval('false ^| false'), 0);
});
it('should parse bitwise or |', function() {
assert.strictEqual(parseAndEval('2 | 6'), 6);
assert.strictEqual(parseAndEval('5 | 3'), 7);
assert.strictEqual(parseAndEval('true | true'), 1);
assert.strictEqual(parseAndEval('true | false'), 1);
assert.strictEqual(parseAndEval('false | true'), 1);
assert.strictEqual(parseAndEval('false | false'), 0);
});
it('should parse bitwise left shift <<', function() {
assert.strictEqual(parseAndEval('23 << 1'), 46);
});
it('should parse bitwise right arithmetic shift >>', function() {
assert.strictEqual(parseAndEval('32 >> 4'), 2);
assert.strictEqual(parseAndEval('-12 >> 2'), -3);
});
it('should parse bitwise right logical shift >>>', function() {
assert.strictEqual(parseAndEval('32 >>> 4'), 2);
assert.strictEqual(parseAndEval('-12 >>> 2'), 1073741821);
});
it('should parse logical and', function() {
assert.strictEqual(parseAndEval('2 and 6'), true);
assert.strictEqual(parseAndEval('2 and 0'), false);
assert.strictEqual(parseAndEval('true and true'), true);
assert.strictEqual(parseAndEval('true and false'), false);
assert.strictEqual(parseAndEval('false and true'), false);
assert.strictEqual(parseAndEval('false and false'), false);
});
it('should parse logical xor', function() {
assert.strictEqual(parseAndEval('2 xor 6'), false);
assert.strictEqual(parseAndEval('2 xor 0'), true);
assert.strictEqual(parseAndEval('true xor true'), false);
assert.strictEqual(parseAndEval('true xor false'), true);
assert.strictEqual(parseAndEval('false xor true'), true);
assert.strictEqual(parseAndEval('false xor false'), false);
});
it('should parse logical or', function() {
assert.strictEqual(parseAndEval('2 or 6'), true);
assert.strictEqual(parseAndEval('2 or 0'), true);
assert.strictEqual(parseAndEval('true or true'), true);
assert.strictEqual(parseAndEval('true or false'), true);
assert.strictEqual(parseAndEval('false or true'), true);
assert.strictEqual(parseAndEval('false or false'), false);
});
it('should parse logical not', function() {
assert.strictEqual(parseAndEval('not 2'), false);
assert.strictEqual(parseAndEval('not not 2'), true);
assert.strictEqual(parseAndEval('not not not 2'), false);
assert.strictEqual(parseAndEval('not true'), false);
assert.strictEqual(parseAndEval('4*not 2'), 0);
assert.strictEqual(parseAndEval('4 * not 2'), 0);
assert.strictEqual(parseAndEval('4-not 2'), 4);
assert.strictEqual(parseAndEval('4 - not 2'), 4);
assert.strictEqual(parseAndEval('4+not 2'), 4);
assert.strictEqual(parseAndEval('4 + not 2'), 4);
assert.strictEqual(parseAndEval('10+not not 3'), 11);
});
it('should parse minus -', function() {
assert.equal(parseAndEval('4 - 2'), 2);
assert.equal(parseAndEval('8 - 2 - 2'), 4);
});
it('should parse unary minus -', function() {
assert.equal(parseAndEval('-2'), -2);
assert.equal(parseAndEval('--2'), 2);
assert.equal(parseAndEval('---2'), -2);
assert.equal(parseAndEval('4*-2'), -8);
assert.equal(parseAndEval('4 * -2'), -8);
assert.equal(parseAndEval('4+-2'), 2);
assert.equal(parseAndEval('4 + -2'), 2);
assert.equal(parseAndEval('4--2'), 6);
assert.equal(parseAndEval('4 - -2'), 6);
assert.equal(parseAndEval('5-3'), 2);
assert.equal(parseAndEval('5--3'), 8);
assert.equal(parseAndEval('5---3'), 2);
assert.equal(parseAndEval('5+---3'), 2);
assert.equal(parseAndEval('5----3'), 8);
assert.equal(parseAndEval('5+--(2+1)'), 8);
});
it('should parse unary +', function() {
assert.equal(parseAndEval('+2'), 2);
assert.equal(parseAndEval('++2'), 2);
assert.equal(parseAndEval('+++2'), 2);
assert.equal(parseAndEval('+true'), 1);
assert.equal(parseAndEval('4*+2'), 8);
assert.equal(parseAndEval('4 * +2'), 8);
assert.equal(parseAndEval('4-+2'), 2);
assert.equal(parseAndEval('4 - +2'), 2);
assert.equal(parseAndEval('4++2'), 6);
assert.equal(parseAndEval('4 + +2'), 6);
assert.equal(parseAndEval('5+3'), 8);
assert.equal(parseAndEval('5++3'), 8);
});
it('should parse unary ~', function() {
assert.equal(parseAndEval('~2'), -3);
assert.equal(parseAndEval('~~2'), 2);
assert.equal(parseAndEval('~~~2'), -3);
assert.equal(parseAndEval('~true'), -2);
assert.equal(parseAndEval('4*~2'), -12);
assert.equal(parseAndEval('4 * ~2'), -12);
assert.equal(parseAndEval('4-~2'), 7);
assert.equal(parseAndEval('4 - ~2'), 7);
assert.equal(parseAndEval('4+~2'), 1);
assert.equal(parseAndEval('4 + ~2'), 1);
assert.equal(parseAndEval('10+~~3'), 13);
});
it('should parse unary plus and minus +, -', function() {
assert.equal(parseAndEval('-+2'), -2);
assert.equal(parseAndEval('-+-2'), 2);
assert.equal(parseAndEval('+-+-2'), 2);
assert.equal(parseAndEval('+-2'), -2);
assert.equal(parseAndEval('+-+2'), -2);
assert.equal(parseAndEval('-+-+2'), 2);
});
it('should parse unary plus and bitwise not +, ~', function() {
assert.equal(parseAndEval('~+2'), -3);
assert.equal(parseAndEval('~+~2'), 2);
assert.equal(parseAndEval('+~+~2'), 2);
assert.equal(parseAndEval('+~2'), -3);
assert.equal(parseAndEval('+~+2'), -3);
assert.equal(parseAndEval('~+~+2'), 2);
});
it('should parse unary minus and bitwise not -, ~', function() {
assert.equal(parseAndEval('~-2'), 1);
assert.equal(parseAndEval('~-~2'), -4);
assert.equal(parseAndEval('-~-~2'), 4);
assert.equal(parseAndEval('-~2'), 3);
assert.equal(parseAndEval('-~-2'), -1);
assert.equal(parseAndEval('~-~-2'), 0);
});
it('should parse unary plus + and logical not', function() {
assert.equal(parseAndEval('not+2'), false);
assert.equal(parseAndEval('not + not 2'), true);
assert.equal(parseAndEval('+not+not 2'), 1);
assert.equal(parseAndEval('+ not 2'), 0);
assert.equal(parseAndEval('+ not +2'), 0);
assert.equal(parseAndEval('not + not +2'), true);
});
it('should parse bitwise not ~ and logical not', function() {
assert.equal(parseAndEval('~not 2'), -1);
assert.equal(parseAndEval('~not~2'), -1);
assert.equal(parseAndEval('not~not~2'), false);
assert.equal(parseAndEval('not~2'), false);
assert.equal(parseAndEval('not~not 2'), false);
assert.equal(parseAndEval('~not~not 2'), -1);
});
it('should parse unary minus and logical not', function() {
assert.equal(parseAndEval('not-2'), false);
assert.equal(parseAndEval('not-not 2'), true);
assert.equal(parseAndEval('-not-not 2'), -1);
assert.equal(parseAndEval('-not 2'), -0);
assert.equal(parseAndEval('-not-2'), -0);
assert.equal(parseAndEval('not-not-2'), true);
});
it('should parse unequal !=', function() {
assert.strictEqual(parseAndEval('2 != 3'), true);
assert.strictEqual(parseAndEval('2 != 2'), false);
assert.deepEqual(parseAndEval('[2,3] != [2,4]'), math.matrix([false, true]));
});
it('should parse conditional expression a ? b : c', function() {
assert.equal(parseAndEval('2 ? true : false'), true);
assert.equal(parseAndEval('0 ? true : false'), false);
assert.equal(parseAndEval('false ? true : false'), false);
assert.equal(parseAndEval('2 > 0 ? 1 : 2 < 0 ? -1 : 0'), 1);
assert.equal(parseAndEval('(2 > 0 ? 1 : 2 < 0) ? -1 : 0'), -1);
assert.equal(parseAndEval('-2 > 0 ? 1 : -2 < 0 ? -1 : 0'), -1);
assert.equal(parseAndEval('0 > 0 ? 1 : 0 < 0 ? -1 : 0'), 0);
});
it('should lazily evaluate conditional expression a ? b : c', function() {
var scope = {};
math.parse('true ? (a = 2) : (b = 2)').compile().eval(scope);
assert.deepEqual(scope, {a: 2});
});
it('should throw an error when false part of conditional expression is missing', function() {
assert.throws(function() {parseAndEval('2 ? true');}, /False part of conditional expression expected/);
});
it('should parse : (range)', function() {
assert.ok(parseAndEval('2:5') instanceof Matrix);
assert.deepEqual(parseAndEval('2:5'), math.matrix([2,3,4,5]));
assert.deepEqual(parseAndEval('10:-2:0'), math.matrix([10,8,6,4,2,0]));
assert.deepEqual(parseAndEval('2:4.0'), math.matrix([2,3,4]));
assert.deepEqual(parseAndEval('2:4.5'), math.matrix([2,3,4]));
assert.deepEqual(parseAndEval('2:4.1'), math.matrix([2,3,4]));
assert.deepEqual(parseAndEval('2:3.9'), math.matrix([2,3]));
assert.deepEqual(parseAndEval('2:3.5'), math.matrix([2,3]));
assert.deepEqual(parseAndEval('3:-1:0.5'), math.matrix([3,2,1]));
assert.deepEqual(parseAndEval('3:-1:0.5'), math.matrix([3,2,1]));
assert.deepEqual(parseAndEval('3:-1:0.1'), math.matrix([3,2,1]));
assert.deepEqual(parseAndEval('3:-1:-0.1'), math.matrix([3,2,1,0]));
});
it('should parse to', function() {
approx.deepEqual(parseAndEval('2.54 cm to inch'), math.unit(1, 'inch').to('inch'));
approx.deepEqual(parseAndEval('2.54 cm + 2 inch to foot'), math.unit(0.25, 'foot').to('foot'));
});
it('should parse in', function() {
approx.deepEqual(parseAndEval('2.54 cm in inch'), math.unit(1, 'inch').to('inch'));
});
it('should parse factorial !', function() {
assert.deepEqual(parseAndEval('5!'), 120);
assert.deepEqual(parseAndEval('[1,2,3,4]!'), math.matrix([1,2,6,24]));
assert.deepEqual(parseAndEval('4!+2'), 26);
assert.deepEqual(parseAndEval('4!-2'), 22);
assert.deepEqual(parseAndEval('4!*2'), 48);
assert.deepEqual(parseAndEval('3!!'), 720);
assert.deepEqual(parseAndEval('[1,2;3,1]!\'!'), math.matrix([[1, 720], [2, 1]]));
assert.deepEqual(parseAndEval('[4,5]![2]'), 120); // index [2]
});
it('should parse transpose \'', function() {
assert.deepEqual(parseAndEval('23\''), 23);
assert.deepEqual(parseAndEval('[1,2,3;4,5,6]\''), math.matrix([[1,4],[2,5],[3,6]]));
assert.ok(parseAndEval('[1,2,3;4,5,6]\'') instanceof Matrix);
assert.deepEqual(parseAndEval('[1:5]'), math.matrix([[1,2,3,4,5]]));
assert.deepEqual(parseAndEval('[1:5]\''), math.matrix([[1],[2],[3],[4],[5]]));
assert.deepEqual(parseAndEval('size([1:5])'), math.matrix([1, 5]));
assert.deepEqual(parseAndEval('[1,2;3,4]\''), math.matrix([[1,3],[2,4]]));
});
describe('operator precedence', function() {
it('should respect precedence of plus and minus', function () {
assert.equal(parseAndEval('4-2+3'), 5);
assert.equal(parseAndEval('4-(2+3)'), -1);
assert.equal(parseAndEval('4-2-3'), -1);
assert.equal(parseAndEval('4-(2-3)'), 5);
});
it('should respect precedence of plus/minus and multiply/divide', function () {
assert.equal(parseAndEval('2+3*4'), 14);
assert.equal(parseAndEval('2*3+4'), 10);
});
it('should respect precedence of plus/minus and pow', function () {
assert.equal(parseAndEval('2+3^2'), 11);
assert.equal(parseAndEval('3^2+2'), 11);
assert.equal(parseAndEval('8-2^2'), 4);
assert.equal(parseAndEval('4^2-2'), 14);
});
it('should respect precedence of multiply/divide and pow', function () {
assert.equal(parseAndEval('2*3^2'), 18);
assert.equal(parseAndEval('3^2*2'), 18);
assert.equal(parseAndEval('8/2^2'), 2);
assert.equal(parseAndEval('4^2/2'), 8);
});
it('should respect precedence of pow', function () {
assert.equal(parseAndEval('2^3'), 8);
assert.equal(parseAndEval('2^3^4'), Math.pow(2, Math.pow(3, 4)));
assert.equal(parseAndEval('1.5^1.5^1.5'), parseAndEval('1.5^(1.5^1.5)'));
assert.equal(parseAndEval('1.5^1.5^1.5^1.5'), parseAndEval('1.5^(1.5^(1.5^1.5))'));
});
it('should respect precedence of unary operations and pow', function () {
assert.equal(parseAndEval('-3^2'), -9);
assert.equal(parseAndEval('(-3)^2'), 9);
assert.equal(parseAndEval('2^-2'), 0.25);
assert.equal(parseAndEval('2^(-2)'), 0.25);
assert.equal(parseAndEval('+3^2'), 9);
assert.equal(parseAndEval('(+3)^2'), 9);
assert.equal(parseAndEval('2^(+2)'), 4);
assert.equal(parseAndEval('~3^2'), -10);
assert.equal(parseAndEval('(~3)^2'), 16);
assert.equal(parseAndEval('2^~2'), 0.125);
assert.equal(parseAndEval('2^(~2)'), 0.125);
assert.equal(parseAndEval('not 3^2'), false);
assert.equal(parseAndEval('(not 3)^2'), 0);
assert.equal(parseAndEval('2^not 2'), 1);
assert.equal(parseAndEval('2^(not 2)'), 1);
});
it('should respect precedence of factorial and pow', function () {
assert.equal(parseAndEval('2^3!'), 64);
assert.equal(parseAndEval('2^(3!)'), 64);
assert.equal(parseAndEval('3!^2'), 36);
});
it('should respect precedence of factorial and unary operations', function () {
assert.equal(parseAndEval('-4!'), -24);
assert.equal(parseAndEval('-(4!)'), -24);
assert.equal(parseAndEval('3!+2'), 8);
assert.equal(parseAndEval('(3!)+2'), 8);
assert.equal(parseAndEval('+4!'), 24);
assert.equal(parseAndEval('~4!+1'), -24);
assert.equal(parseAndEval('~(4!)+1'), -24);
assert.equal(parseAndEval('not 4!'), false);
assert.equal(parseAndEval('not not 4!'), true);
assert.equal(parseAndEval('not(4!)'), false);
assert.equal(parseAndEval('(not 4!)'), false);
assert.equal(parseAndEval('(not 4)!'), 1);
});
it('should respect precedence of transpose', function () {
var node = math.parse('a + b\'');
assert(node instanceof OperatorNode);
assert.equal(node.op, '+');
assert.equal(node.args[0].toString(), 'a');
assert.equal(node.args[1].toString(), 'b\'');
});
it('should respect precedence of transpose (2)', function () {
var node = math.parse('a ^ b\'');
assert(node instanceof OperatorNode);
assert.equal(node.op, '^');
assert.equal(node.args[0].toString(), 'a');
assert.equal(node.args[1].toString(), 'b\'');
});
it('should respect precedence of conditional operator and other operators', function () {
assert.equal(parseAndEval('2 > 3 ? true : false'), false);
assert.equal(parseAndEval('2 == 3 ? true : false'), false);
assert.equal(parseAndEval('3 ? 2 + 4 : 2 - 1'), 6);
assert.deepEqual(parseAndEval('3 ? true : false; 22'), new ResultSet([22]));
assert.deepEqual(parseAndEval('3 ? 5cm to m : 5cm in mm'), new Unit(5, 'cm').to('m'));
assert.deepEqual(parseAndEval('2 == 4-2 ? [1,2] : false'), math.matrix([1,2]));
assert.deepEqual(parseAndEval('false ? 1:2:6'), math.matrix([2,3,4,5,6]));
});
it('should respect precedence between left/right shift and relational operators', function () {
assert.strictEqual(parseAndEval('32 >> 4 == 2'), true);
assert.strictEqual(parseAndEval('2 == 32 >> 4'), true);
assert.strictEqual(parseAndEval('2 << 2 == 8'), true);
assert.strictEqual(parseAndEval('8 == 2 << 2'), true);
});
it('should respect precedence between relational operators and bitwise and', function () {
assert.strictEqual(parseAndEval('2 == 3 & 1'), 0);
assert.strictEqual(parseAndEval('3 & 1 == 2'), 0);
assert.strictEqual(parseAndEval('2 == (3 & 1)'), false);
});
it('should respect precedence between bitwise or | and logical and', function () {
assert.strictEqual(parseAndEval('2 | 2 and 4'), true);
assert.strictEqual(parseAndEval('4 and 2 | 2'), true);
});
it('should respect precedence between bitwise xor ^| and bitwise or |', function () {
assert.strictEqual(parseAndEval('4 ^| 6 | 2'), 2);
assert.strictEqual(parseAndEval('2 | 4 ^| 6'), 2);
assert.strictEqual(parseAndEval('(2 | 4) ^| 6'), 0);
});
it('should respect precedence between bitwise and & and bitwise or |', function () {
assert.strictEqual(parseAndEval('4 & 3 | 12'), 12);
assert.strictEqual(parseAndEval('12 | 4 & 3'), 12);
assert.strictEqual(parseAndEval('(12 | 4) & 3'), 0);
});
it('should respect precedence between logical and and or', function () {
assert.strictEqual(parseAndEval('false and true or true'), true);
assert.strictEqual(parseAndEval('false and (true or true)'), false);
assert.strictEqual(parseAndEval('true or true and false'), true);
assert.strictEqual(parseAndEval('(true or true) and false'), false);
});
it('should respect precedence of conditional operator and logical or', function () {
var node = math.parse('1 or 0 ? 2 or 3 : 0 or 0');
assert(node instanceof ConditionalNode);
assert.equal(node.condition.toString(), '1 or 0');
assert.equal(node.trueExpr.toString(), '2 or 3');
assert.equal(node.falseExpr.toString(), '0 or 0');
assert.strictEqual(node.compile().eval(), true);
});
it('should respect precedence of conditional operator and relational operators', function () {
var node = math.parse('a == b ? a > b : a < b');
assert(node instanceof ConditionalNode);
assert.equal(node.condition.toString(), 'a == b');
assert.equal(node.trueExpr.toString(), 'a > b');
assert.equal(node.falseExpr.toString(), 'a < b');
});
it('should respect precedence of conditional operator and range operator', function () {
var node = math.parse('a ? b : c : d');
assert(node instanceof ConditionalNode);
assert.equal(node.condition.toString(), 'a');
assert.equal(node.trueExpr.toString(), 'b');
assert.equal(node.falseExpr.toString(), 'c:d');
});
it('should respect precedence of conditional operator and range operator (2)', function () {
var node = math.parse('a ? (b : c) : (d : e)');
assert(node instanceof ConditionalNode);
assert.equal(node.condition.toString(), 'a');
assert.equal(node.trueExpr.toString(), '(b:c)');
assert.equal(node.falseExpr.toString(), '(d:e)');
});
it('should respect precedence of conditional operator and range operator (2)', function () {
var node = math.parse('a ? (b ? c : d) : (e ? f : g)');
assert(node instanceof ConditionalNode);
assert.equal(node.condition.toString(), 'a');
assert.equal(node.trueExpr.toString(), '(b ? c : d)');
assert.equal(node.falseExpr.toString(), '(e ? f : g)');
});
it('should respect precedence of range operator and relational operators', function () {
var node = math.parse('a:b == c:d');
assert(node instanceof OperatorNode);
assert.equal(node.args[0].toString(), 'a:b');
assert.equal(node.args[1].toString(), 'c:d');
});
it('should respect precedence of range operator and operator plus and minus', function () {
var node = math.parse('a + b : c - d');
assert(node instanceof RangeNode);
assert.equal(node.start.toString(), 'a + b');
assert.equal(node.end.toString(), 'c - d');
});
it('should respect precedence of "to" operator and relational operators', function () {
var node = math.parse('a == b to c');
assert(node instanceof OperatorNode);
assert.equal(node.args[0].toString(), 'a');
assert.equal(node.args[1].toString(), 'b to c');
});
it('should respect precedence of "to" operator and relational operators (2)', function () {
var node = math.parse('a to b == c');
assert(node instanceof OperatorNode);
assert.equal(node.args[0].toString(), 'a to b');
assert.equal(node.args[1].toString(), 'c');
});
// TODO: extensively test operator precedence
});
});
describe('functions', function () {
it('should evaluate function "mod"', function () {
approx.equal(parseAndEval('mod(8, 3)'), 2);
});
it('should evaluate function "to" ', function () {
approx.deepEqual(parseAndEval('to(5.08 cm * 1000, inch)'),
math.unit(2000, 'inch').to('inch'));
});
it('should evaluate function "sort" with a custom sort function', function () {
var scope = {};
parseAndEval('sortByLength(a, b) = size(a)[1] - size(b)[1]', scope);
assert.deepEqual(parseAndEval('sort(["Langdon", "Tom", "Sara"], sortByLength)', scope),
math.matrix(["Tom", "Sara", "Langdon"]));
});
it('should evaluate function "filter" with a custom test function', function () {
var scope = {};
parseAndEval('isPositive(x) = x > 0', scope);
assert.deepEqual(parseAndEval('filter([6, -2, -1, 4, 3], isPositive)', scope),
math.matrix([6, 4, 3]));
});
it('should evaluate function "filter" with a custom test equation', function () {
assert.deepEqual(parseAndEval('filter([6, -2, -1, 4, 3], x > 0)'),
math.matrix([6, 4, 3]));
});
});
describe('bignumber', function () {
var bigmath = math.create({
number: 'BigNumber'
});
var BigNumber = bigmath.type.BigNumber;
it('should parse numbers as bignumber', function() {
assert.deepEqual(bigmath.bignumber('2.3'), new BigNumber('2.3'));
assert.deepEqual(bigmath.eval('2.3'), new BigNumber('2.3'));
assert.deepEqual(bigmath.eval('2.3e+500'), new BigNumber('2.3e+500'));
});
it('should evaluate functions supporting bignumbers', function() {
assert.deepEqual(bigmath.eval('0.1 + 0.2'), new BigNumber('0.3'));
});
it('should evaluate functions supporting bignumbers', function() {
assert.deepEqual(bigmath.eval('add(0.1, 0.2)'), new BigNumber('0.3'));
});
it('should work with mixed numbers and bignumbers', function() {
approx.equal(bigmath.eval('pi + 1'), 4.141592653589793);
});
it('should evaluate functions not supporting bignumbers', function() {
approx.equal(bigmath.eval('sin(0.1)'), 0.09983341664682815);
});
it('should create a range from bignumbers', function() {
assert.deepEqual(bigmath.eval('4:6'),
bigmath.matrix([new BigNumber(4), new BigNumber(5), new BigNumber(6)]));
assert.deepEqual(bigmath.eval('0:2:4'),
bigmath.matrix([new BigNumber(0), new BigNumber(2), new BigNumber(4)]));
});
it('should create a matrix with bignumbers', function() {
assert.deepEqual(bigmath.eval('[0.1, 0.2]'),
bigmath.matrix([new BigNumber(0.1), new BigNumber(0.2)]));
});
it('should get an element from a matrix with bignumbers', function() {
var scope = {};
assert.deepEqual(bigmath.eval('a=[0.1, 0.2]', scope),
bigmath.matrix([new BigNumber(0.1), new BigNumber(0.2)]));
assert.deepEqual(bigmath.eval('a[1]', scope), new BigNumber(0.1));
assert.deepEqual(bigmath.eval('a[:]', scope),
bigmath.matrix([new BigNumber(0.1), new BigNumber(0.2)]));
assert.deepEqual(bigmath.eval('a[1:2]', scope),
bigmath.matrix([new BigNumber(0.1), new BigNumber(0.2)]));
});
it('should replace elements in a matrix with bignumbers', function() {
var scope = {};
assert.deepEqual(bigmath.eval('a=[0.1, 0.2]', scope),
bigmath.matrix([new BigNumber(0.1), new BigNumber(0.2)]));
bigmath.eval('a[1] = 0.3', scope);
assert.deepEqual(scope.a, bigmath.matrix([new BigNumber(0.3), new BigNumber(0.2)]));
bigmath.eval('a[:] = [0.5, 0.6]', scope);
assert.deepEqual(scope.a, bigmath.matrix([new BigNumber(0.5), new BigNumber(0.6)]));
bigmath.eval('a[1:2] = [0.7, 0.8]', scope);
assert.deepEqual(scope.a, bigmath.matrix([new BigNumber(0.7), new BigNumber(0.8)]));
});
it('should work with complex numbers (downgrades bignumbers to number)', function() {
assert.deepEqual(bigmath.eval('3i'), new Complex(0, 3));
assert.deepEqual(bigmath.eval('2 + 3i'), new Complex(2, 3));
assert.deepEqual(bigmath.eval('2 * i'), new Complex(0, 2));
});
it('should work with units', function() {
assert.deepEqual(bigmath.eval('2 cm'), new Unit(new BigNumber(2), 'cm'));
});
});
describe('scope', function () {
it('should use a given scope for assignments', function() {
var scope = {
a: 3,
b: 4
};
assert.deepEqual(parse('a*b').compile().eval(scope), 12);
assert.deepEqual(parse('c=5').compile().eval(scope), 5);
assert.deepEqual(parse('f(x) = x^a').compile().eval(scope).syntax, 'f(x)');
assert.deepEqual(Object.keys(scope).length, 4);
assert.deepEqual(scope.a, 3);
assert.deepEqual(scope.b, 4);
assert.deepEqual(scope.c, 5);
assert.deepEqual(typeof scope.f, 'function');
assert.equal(scope.f(3), 27);
scope.a = 2;
assert.equal(scope.f(3), 9);
scope.hello = function (name) {
return 'hello, ' + name + '!';
};
assert.deepEqual(parse('hello("jos")').compile().eval(scope), 'hello, jos!');
});
it('should parse undefined symbols, defining symbols, and removing symbols', function() {
var scope = {};
var n = parse('q');
assert.throws(function () { n.compile().eval(scope); });
parse('q=33').compile().eval(scope);
assert.equal(n.compile().eval(scope), 33);
delete scope.q;
assert.throws(function () { n.compile().eval(scope); });
n = parse('qq[1,1]=33');
assert.throws(function () { n.compile().eval(scope); });
parse('qq=[1,2;3,4]').compile().eval(scope);
n.compile().eval(scope);
assert.deepEqual(scope.qq, math.matrix([[33,2],[3,4]]));
parse('qq=[4]').compile().eval(scope);
n.compile().eval(scope);
assert.deepEqual(scope.qq, math.matrix([[33]]));
delete scope.qq;
assert.throws(function () { n.compile().eval(scope); });
});
it('should evaluate a symbol with value null or undefined', function () {
assert.equal(parse('a').compile().eval({a: null}), null);
assert.equal(parse('a').compile().eval({a: undefined}), undefined);
});
});
describe('errors', function () {
it('should return IndexErrors with one based indices', function () {
// functions throw a zero-based error
assert.throws(function () {math.subset([1,2,3], math.index(4));}, /Index out of range \(4 > 2\)/);
assert.throws(function () {math.subset([1,2,3], math.index(-2));}, /Index out of range \(-2 < 0\)/);
// evaluation via parser throws one-based error
assert.throws(function () {math.eval('A[4]', {A:[1,2,3]});}, /Index out of range \(4 > 3\)/);
assert.throws(function () {math.eval('A[-2]', {A: [1,2,3]});}, /IndexError: Index out of range \(-2 < 1\)/);
});
it('should return DimensionErrors with one based indices (subset)', function () {
// TODO: it would be more clear when all errors where DimensionErrors
// functions throw a zero-based error
assert.throws(function () {math.subset([1,2,3], math.index(1,1));}, /DimensionError: Dimension mismatch \(2 != 1\)/);
// evaluation via parser throws one-based error
assert.throws(function () {math.eval('A[1,1]', {A: [1,2,3]});}, /DimensionError: Dimension mismatch \(2 != 1\)/);
});
it('should return DimensionErrors with one based indices (concat)', function () {
// TODO: it would be more clear when all errors where DimensionErrors
// functions throw a zero-based error
assert.throws(function () {math.concat([1,2], [[3,4]]);}, /DimensionError: Dimension mismatch \(1 != 2\)/);
assert.throws(function () {math.concat([[1,2]], [[3,4]], 2);}, /IndexError: Index out of range \(2 > 1\)/);
assert.throws(function () {math.concat([[1,2]], [[3,4]], -1);}, /IndexError: Index out of range \(-1 < 0\)/);
// evaluation via parser throws one-based error
assert.throws(function () {math.eval('concat([1,2], [[3,4]])');}, /DimensionError: Dimension mismatch \(1 != 2\)/);
assert.throws(function () {math.eval('concat([[1,2]], [[3,4]], 3)');}, /IndexError: Index out of range \(3 > 2\)/);
assert.throws(function () {math.eval('concat([[1,2]], [[3,4]], 0)');}, /IndexError: Index out of range \(0 < 1\)/);
});
it('should return DimensionErrors with one based indices (max)', function () {
// TODO: it would be more clear when all errors where DimensionErrors
// functions throw a zero-based error
// TODO
// evaluation via parser throws one-based error
assert.deepEqual(math.eval('max([[1,2], [3,4]])'), 4);
assert.deepEqual(math.eval('max([[1,2], [3,4]], 1)'), math.matrix([3, 4]));
assert.deepEqual(math.eval('max([[1,2], [3,4]], 2)'), math.matrix([2, 4]));
assert.throws(function () {math.eval('max([[1,2], [3,4]], 3)');}, /IndexError: Index out of range \(3 > 2\)/);
assert.throws(function () {math.eval('max([[1,2], [3,4]], 0)');}, /IndexError: Index out of range \(0 < 1\)/);
});
it('should return DimensionErrors with one based indices (min)', function () {
// TODO: it would be more clear when all errors where DimensionErrors
// functions throw a zero-based error
// TODO
// evaluation via parser throws one-based error
assert.deepEqual(math.eval('min([[1,2], [3,4]])'), 1);
assert.deepEqual(math.eval('min([[1,2], [3,4]], 1)'), math.matrix([1, 2]));
assert.deepEqual(math.eval('min([[1,2], [3,4]], 2)'), math.matrix([1, 3]));
assert.throws(function () {math.eval('min([[1,2], [3,4]], 3)');}, /IndexError: Index out of range \(3 > 2\)/);
assert.throws(function () {math.eval('min([[1,2], [3,4]], 0)');}, /IndexError: Index out of range \(0 < 1\)/);
});
it('should return DimensionErrors with one based indices (mean)', function () {
// TODO: it would be more clear when all errors where DimensionErrors
// functions throw a zero-based error
// TODO
// evaluation via parser throws one-based error
assert.deepEqual(math.eval('mean([[1,2], [3,4]])'), 2.5);
assert.deepEqual(math.eval('mean([[1,2], [3,4]], 1)'), math.matrix([2, 3]));
assert.deepEqual(math.eval('mean([[1,2], [3,4]], 2)'), math.matrix([1.5, 3.5]));
assert.throws(function () {math.eval('mean([[1,2], [3,4]], 3)');}, /IndexError: Index out of range \(3 > 2\)/);
assert.throws(function () {math.eval('mean([[1,2], [3,4]], 0)');}, /IndexError: Index out of range \(0 < 1\)/);
});
});
describe('node tree', function () {
// TODO: test parsing into a node tree
it('should correctly stringify a node tree', function() {
assert.equal(parse('0').toString(), '0');
assert.equal(parse('"hello"').toString(), '"hello"');
assert.equal(parse('[1, 2 + 3i, 4]').toString(), '[1, 2 + 3 i, 4]');
assert.equal(parse('1/2a').toString(), '1 / 2 a');
});
it('should correctly stringify an index with dot notation', function() {
assert.equal(parse('A[2]').toString(), 'A[2]');
assert.equal(parse('a["b"]').toString(), 'a["b"]');
assert.equal(parse('a.b').toString(), 'a.b');
});
describe('custom nodes', function () {
// define a custom node
function CustomNode (args) {
this.args = args;
}
CustomNode.prototype = new math.expression.node.Node();
CustomNode.prototype.toString = function () {
return 'CustomNode';
};
CustomNode.prototype._compile = function (defs) {
var strArgs = [];
this.args.forEach(function (arg) {
strArgs.push(arg.toString());
});
return '"CustomNode(' + strArgs.join(', ') + ')"';
};
CustomNode.prototype.forEach = function (callback) {
// we don't have childs
};
var options = {
nodes: {
custom: CustomNode
}
};
it('should parse custom nodes', function() {
var node = parse('custom(x, (2+x), sin(x))', options);
assert.equal(node.compile().eval(), 'CustomNode(x, (2 + x), sin(x))');
});
it('should parse custom nodes without parameters', function() {
var node = parse('custom()', options);
assert.equal(node.compile().eval(), 'CustomNode()');
assert.equal(node.filter(function (node) {return node instanceof CustomNode;}).length, 1);
var node2 = parse('custom', options);
assert.equal(node2.compile().eval(), 'CustomNode()');
assert.equal(node2.filter(function (node) {return node instanceof CustomNode;}).length, 1);
});
it('should throw an error on syntax errors in using custom nodes', function() {
assert.throws(function () {parse('custom(x', options);}, /Parenthesis \) expected/);
assert.throws(function () {parse('custom(x, ', options);}, /Unexpected end of expression/);
});
});
});
describe ('expose test functions', function () {
it('should expose isAlpha', function() {
assert.ok('should expose isAlpha', typeof math.expression.parse.isAlpha === 'function')
});
it('should expose isValidLatinOrGreek', function() {
assert.ok('should expose isAlpha', typeof math.expression.parse.isValidLatinOrGreek === 'function')
});
it('should expose isValidMathSymbol', function() {
assert.ok('should expose isAlpha', typeof math.expression.parse.isValidMathSymbol === 'function')
});
it('should expose isWhitespace', function() {
assert.ok('should expose isAlpha', typeof math.expression.parse.isWhitespace === 'function')
});
it('should expose isDecimalMark', function() {
assert.ok('should expose isAlpha', typeof math.expression.parse.isDecimalMark === 'function')
});
it('should expose isDigitDot', function() {
assert.ok('should expose isAlpha', typeof math.expression.parse.isDigitDot === 'function')
});
it('should expose isDigit', function() {
assert.ok('should expose isAlpha', typeof math.expression.parse.isDigit === 'function')
});
it('should allow overriding isAlpha', function() {
var originalIsAlpha = math.expression.parse.isAlpha;
// override isAlpha with one accepting $ characters too
math.expression.parse.isAlpha = function (c, cPrev, cNext) {
return /^[a-zA-Z_$]$/.test(c)
};
const node = math.expression.parse('$foo');
const result = node.eval({$foo: 42});
assert.equal(result, 42);
// restore original isAlpha
math.expression.parse.isAlpha = originalIsAlpha
});
});
});

View File

@@ -0,0 +1,389 @@
// test lup
var assert = require('assert'),
approx = require('../../../../tools/approx'),
math = require('../../../../index');
describe('lup', function () {
it('should decompose matrix, n x n, no permutations, array', function () {
var m = [[2, 1], [1, 4]];
var r = math.lup(m);
// L
assert.deepEqual(r.L.valueOf(), [[1, 0], [0.5, 1]]);
// U
assert.deepEqual(r.U.valueOf(), [[2, 1], [0, 3.5]]);
// P
assert.deepEqual(r.p, [0, 1]);
// verify
approx.deepEqual(math.multiply(_p(r.p), m).valueOf(), math.multiply(r.L, r.U).valueOf());
});
it('should decompose matrix, n x n, no permutations, sparse', function () {
var m = math.matrix([[2, 1], [1, 4]], 'sparse');
var r = math.lup(m);
// L
assert.deepEqual(r.L.valueOf(), [[1, 0], [0.5, 1]]);
// U
assert.deepEqual(r.U.valueOf(), [[2, 1], [0, 3.5]]);
// P
assert.deepEqual(r.p, [0, 1]);
// verify
approx.deepEqual(math.multiply(_p(r.p), m).valueOf(), math.multiply(r.L, r.U).valueOf());
});
it('should decompose matrix, n x n, no permutations, dense format', function () {
var m = math.matrix([[2, 1], [1, 4]], 'dense');
var r = math.lup(m);
// L
assert.deepEqual(r.L.valueOf(), [[1, 0], [0.5, 1]]);
// U
assert.deepEqual(r.U.valueOf(), [[2, 1], [0, 3.5]]);
// P
assert.deepEqual(r.p, [0, 1]);
// verify
approx.deepEqual(math.multiply(_p(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 () {
var m = math.matrix(
[
[2, 1, 1],
[1, 4, 5]
]
);
var r = math.lup(m);
// L
assert.deepEqual(
r.L,
math.matrix(
[
[1, 0],
[0.5, 1]
]
));
// U
assert.deepEqual(
r.U,
math.matrix(
[
[2, 1, 1],
[0, 3.5, 4.5]
]
));
// P
assert.deepEqual(r.p, [0, 1]);
// verify
approx.deepEqual(math.multiply(_p(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 () {
var m = math.matrix(
[
[8, 2],
[6, 4],
[4, 1]
]
);
var r = math.lup(m);
// L
assert.deepEqual(
r.L,
math.matrix(
[
[1, 0],
[0.75, 1],
[0.5, 0]
]
));
// U
assert.deepEqual(
r.U,
math.matrix(
[
[8, 2],
[0, 2.5]
]
));
// P
assert.deepEqual(r.p, [0, 1, 2]);
// verify
approx.deepEqual(math.multiply(_p(r.p), m).valueOf(), math.multiply(r.L, r.U).valueOf());
});
it('should decompose matrix, n x n, dense format', function () {
var m = math.matrix(
[
[16, -120, 240, -140],
[-120, 1200, -2700, 1680],
[240, -2700, 6480, -4200],
[-140, 1680, -4200, 2800]
]
);
var r = math.lup(m);
// L
approx.deepEqual(
r.L.valueOf(),
[
[1, 0, 0, 0],
[-0.5, 1, 0, 0],
[-0.5833333333333334, -0.7, 1, 0],
[0.06666666666666667, -0.4, -0.5714285714285776, 1]
]);
// U
approx.deepEqual(
r.U.valueOf(),
[
[240, -2700, 6480, -4200],
[0, -150, 540, -420],
[0, 0, -42, 56],
[0, 0, 0, 4]
]);
// P
assert.deepEqual(r.p, [3, 1, 0, 2]);
// verify
approx.deepEqual(math.multiply(_p(r.p), m).valueOf(), math.multiply(r.L, r.U).valueOf());
});
it('should decompose matrix, 3 x 3, zero pivote value, dense format', function () {
var m = math.matrix(
[
[1, 2, 3],
[2, 4, 6],
[4, 8, 9]
]);
var r = math.lup(m);
// L
approx.deepEqual(
r.L.valueOf(),
[
[1, 0, 0],
[0.5, 1, 0],
[0.25, 0, 1.0]
]);
// U
approx.deepEqual(
r.U.valueOf(),
[
[4, 8, 9],
[0, 0, 1.5],
[0, 0, 0.75]
]);
// P
assert.deepEqual(r.p, [2, 1, 0]);
// verify
approx.deepEqual(math.multiply(_p(r.p), m).valueOf(), math.multiply(r.L, r.U).valueOf());
});
it('should decompose matrix, 3 x 2, complex numbers, dense format', function () {
var m = math.matrix(
[
[math.complex(0, 3), 10],
[math.complex(0, 1), 1],
[math.complex(0, 1), 1]
]);
var r = math.lup(m);
// L
approx.deepEqual(
r.L.valueOf(),
[
[1, 0],
[math.complex(0.3333333, 0), 1],
[math.complex(0.3333333, 0), 1]
]);
// U
approx.deepEqual(
r.U.valueOf(),
[
[math.complex(0, 3), 10],
[0, math.complex(-2.3333333333, 0)]
]);
// P
assert.deepEqual(r.p, [0, 1, 2]);
// verify
approx.deepEqual(math.multiply(_p(r.p), m).valueOf(), math.multiply(r.L, r.U).valueOf());
});
it('should decompose matrix, m x n, m < n, no permutations, sparse', function () {
var m = math.matrix(
[
[2, 1, 1],
[1, 4, 5]
],
'sparse');
var r = math.lup(m);
// L
assert.deepEqual(
r.L.valueOf(),
[
[1, 0],
[0.5, 1]
]);
// U
assert.deepEqual(
r.U.valueOf(),
[
[2, 1, 1],
[0, 3.5, 4.5]
]);
// P
assert.deepEqual(r.p, [0, 1]);
// verify
approx.deepEqual(math.multiply(_p(r.p), m).valueOf(), math.multiply(r.L, r.U).valueOf());
});
it('should decompose matrix, m x n, m > n, no permutations, sparse', function () {
var m = math.matrix(
[
[8, 2],
[6, 4],
[4, 1]
],
'sparse');
var r = math.lup(m);
// L
assert.deepEqual(
r.L.valueOf(),
[
[1, 0],
[0.75, 1],
[0.5, 0]
]);
// U
assert.deepEqual(
r.U.valueOf(),
[
[8, 2],
[0, 2.5]
]);
// P
assert.deepEqual(r.p, [0, 1, 2]);
// verify
approx.deepEqual(math.multiply(_p(r.p), m).valueOf(), math.multiply(r.L, r.U).valueOf());
});
it('should decompose matrix, n x n, sparse', function () {
var m = math.matrix(
[
[16, -120, 240, -140],
[-120, 1200, -2700, 1680],
[240, -2700, 6480, -4200],
[-140, 1680, -4200, 2800]
],
'sparse');
var r = math.lup(m);
// L
approx.deepEqual(
r.L.valueOf(),
[
[1, 0, 0, 0],
[-0.5, 1, 0, 0],
[-0.5833333333333334, -0.7, 1, 0],
[0.06666666666666667, -0.4, -0.5714285714285776, 1]
]);
// U
approx.deepEqual(
r.U.valueOf(),
[
[240, -2700, 6480, -4200],
[0, -150, 540, -420],
[0, 0, -42, 56],
[0, 0, 0, 4]
]);
// P
assert.deepEqual(r.p, [3, 1, 0, 2]);
// verify
approx.deepEqual(math.multiply(_p(r.p), m).valueOf(), math.multiply(r.L, r.U).valueOf());
});
it('should decompose matrix, 3 x 3, zero pivote value, sparse', function () {
var m = math.matrix(
[
[1, 2, 3],
[2, 4, 6],
[4, 8, 9]
],
'sparse');
var r = math.lup(m);
// L
approx.deepEqual(
r.L.valueOf(),
[
[1, 0, 0],
[0.5, 1, 0],
[0.25, 0, 1.0]
]);
// U
approx.deepEqual(
r.U.valueOf(),
[
[4, 8, 9],
[0, 0, 1.5],
[0, 0, 0.75]
]);
// P
assert.deepEqual(r.p, [2, 1, 0]);
// verify
approx.deepEqual(math.multiply(_p(r.p), m).valueOf(), math.multiply(r.L, r.U).valueOf());
});
it('should decompose matrix, 3 x 2, complex numbers, sparse', function () {
var m = math.matrix(
[
[math.complex(0, 3), 10],
[math.complex(0, 1), 1],
[math.complex(0, 1), 1]
], 'sparse');
var r = math.lup(m);
// L
approx.deepEqual(
r.L.valueOf(),
[
[1, 0],
[math.complex(0.3333333, 0), 1],
[math.complex(0.3333333, 0), 1]
]);
// U
approx.deepEqual(
r.U.valueOf(),
[
[math.complex(0, 3), 10],
[0, math.complex(-2.3333333333, 0)]
]);
// P
assert.deepEqual(r.p, [0, 1, 2]);
// verify
approx.deepEqual(math.multiply(_p(r.p), m).valueOf(), math.multiply(r.L, r.U).valueOf());
});
/**
* Creates a Matrix out of a row permutation vector
*/
function _p(p) {
// identity matrix
var identity = math.eye(p.length);
// array
var data = [];
// loop rows
for (var i = 0, l = p.length; i < l; i++) {
// swap row
data[p[i]] = identity._data[i];
}
return data;
}
});

View File

@@ -0,0 +1,199 @@
var approx = require('../../../../tools/approx'),
math = require('../../../../index'),
market = require('../../../../tools/matrixmarket');
describe('slu', function () {
it('should decompose matrix, 4 x 4, natural ordering (order=0), partial pivoting', function () {
var m = math.sparse(
[
[4.5, 0, 3.2, 0],
[3.1, 2.9, 0, 0.9],
[0, 1.7, 3, 0],
[3.5, 0.4, 0, 1]
]);
// partial pivoting
var r = math.slu(m, 0, 1);
// verify M[p,q]=L*U
approx.deepEqual(_permute(m, r.p, r.q).valueOf(), math.multiply(r.L, r.U).valueOf());
});
it('should decompose matrix, 4 x 4, amd(A+A\') (order=1)', function () {
var m = math.sparse(
[
[4.5, 0, 3.2, 0],
[3.1, 2.9, 0, 0.9],
[0, 1.7, 3, 0],
[3.5, 0.4, 0, 1]
]);
// partial pivoting
var r = math.slu(m, 1, 1);
// verify M[p,q]=L*U
approx.deepEqual(_permute(m, r.p, r.q).valueOf(), math.multiply(r.L, r.U).valueOf());
});
it('should decompose matrix, 4 x 4, amd(A\'*A) (order=2), partial pivoting', function () {
var m = math.sparse(
[
[4.5, 0, 3.2, 0],
[3.1, 2.9, 0, 0.9],
[0, 1.7, 3, 0],
[3.5, 0.4, 0, 1]
]);
// partial pivoting
var r = math.slu(m, 2, 1);
// verify M[p,q]=L*U
approx.deepEqual(_permute(m, r.p, r.q).valueOf(), math.multiply(r.L, r.U).valueOf());
});
it('should decompose matrix, 4 x 4, amd(A\'*A) (order=3), partial pivoting', function () {
var m = math.sparse(
[
[4.5, 0, 3.2, 0],
[3.1, 2.9, 0, 0.9],
[0, 1.7, 3, 0],
[3.5, 0.4, 0, 1]
]);
// partial pivoting
var r = math.slu(m, 3, 1);
// verify M[p,q]=L*U
approx.deepEqual(_permute(m, r.p, r.q).valueOf(), math.multiply(r.L, r.U).valueOf());
});
it('should decompose matrix, 48 x 48, natural ordering (order=0), full pivoting, matrix market', function (done) {
// import matrix
market.import('tools/matrices/bcsstk01.tar.gz', ['bcsstk01/bcsstk01.mtx'])
.then(function (matrices) {
// matrix
var m = matrices[0];
// full pivoting
var r = math.slu(m, 0, 0.001);
// verify M[p,q]=L*U
approx.deepEqual(_permute(m, r.p, r.q).valueOf(), math.multiply(r.L, r.U).valueOf());
// indicate test has completed
done();
})
.fail(function (error) {
// indicate test has completed
done(error);
});
});
it('should decompose matrix, 48 x 48, amd(A+A\') (order=1), full pivoting, matrix market', function (done) {
// import matrix
market.import('tools/matrices/bcsstk01.tar.gz', ['bcsstk01/bcsstk01.mtx'])
.then(function (matrices) {
// matrix
var m = matrices[0];
// full pivoting
var r = math.slu(m, 1, 0.001);
// verify M[p,q]=L*U
approx.deepEqual(_permute(m, r.p, r.q).valueOf(), math.multiply(r.L, r.U).valueOf());
// indicate test has completed
done();
})
.fail(function (error) {
// indicate test has completed
done(error);
});
});
it('should decompose matrix, 48 x 48, amd(A\'*A) (order=2), full pivoting, matrix market', function (done) {
// import matrix
market.import('tools/matrices/bcsstk01.tar.gz', ['bcsstk01/bcsstk01.mtx'])
.then(function (matrices) {
// matrix
var m = matrices[0];
// full pivoting
var r = math.slu(m, 2, 0.001);
// verify M[p,q]=L*U
approx.deepEqual(_permute(m, r.p, r.q).valueOf(), math.multiply(r.L, r.U).valueOf());
// indicate test has completed
done();
})
.fail(function (error) {
// indicate test has completed
done(error);
});
});
it('should decompose matrix, 48 x 48, amd(A\'*A) (order=3), full pivoting, matrix market', function (done) {
// import matrix
market.import('tools/matrices/bcsstk01.tar.gz', ['bcsstk01/bcsstk01.mtx'])
.then(function (matrices) {
// matrix
var m = matrices[0];
// full pivoting
var r = math.slu(m, 3, 0.001);
// verify M[p,q]=L*U
approx.deepEqual(_permute(m, r.p, r.q).valueOf(), math.multiply(r.L, r.U).valueOf());
// indicate test has completed
done();
})
.fail(function (error) {
// indicate test has completed
done(error);
});
});
/**
* C = A(p,q) where p is the row permutation vector and q the column permutation vector.
*/
var _permute = function (A, pinv, q) {
// matrix arrays
var values = A._values;
var index = A._index;
var ptr = A._ptr;
var size = A._size;
// columns
var n = size[1];
// c arrays
var cvalues = [];
var cindex = [];
var cptr = [];
// loop columns
for (var k = 0 ; k < n ; k++) {
cptr[k] = cindex.length;
// column in C
var j = q ? (q[k]) : k;
// values in column j
for (var t = ptr[j]; t < ptr[j + 1]; t++) {
cvalues.push(values[t]);
cindex.push(pinv ? (pinv[index[t]]) : index[t]);
}
}
cptr[n] = cindex.length;
// return matrix
return new math.type.SparseMatrix({
values: cvalues,
index: cindex,
ptr: cptr,
size: size,
datatype: A._datatype
});
};
});

View File

@@ -0,0 +1,234 @@
// test derivative
var assert = require('assert');
var math = require('../../../index');
var OperatorNode = math.expression.node.OperatorNode;
var derivative = math.derivative;
describe('derivative', function() {
function derivativeWithoutSimplify (expr, value) {
return math.derivative(expr, value, {simplify: false});
}
function compareString(left, right) {
assert.equal(left.toString(), right.toString());
}
it('should take the derivative of a constant', function() {
compareString(derivativeWithoutSimplify('1', 'x'), '0');
compareString(derivativeWithoutSimplify('10000000', 'x'), '0');
});
it('should reckon with option simplify', function() {
compareString(derivative('2x', 'x'), '2'); // default of simplify is true
compareString(derivative('2x', 'x', {simplify: true}), '2');
compareString(derivative('2x', 'x', {simplify: false}), '2 * 1');
});
it('should create a function node', function() {
compareString(derivative('sin(2x)', 'x'), '2 * cos(2 * x)');
});
it('should take the derivative of a SymbolNodes', function() {
compareString(derivativeWithoutSimplify('x', 'x'), '1');
});
it('should maintain parenthesis of ParenthesisNodes', function() {
compareString(derivativeWithoutSimplify('(1)', 'x'), '(0)');
compareString(derivativeWithoutSimplify('(x)', 'x'), '(1)');
});
it('should take the derivative of FunctionAssignmentNodes', function() {
compareString(derivativeWithoutSimplify('f(x) = 5x + x + 2', 'x'), '5 * 1 + 1 + 0');
compareString(derivativeWithoutSimplify('f(x) = 5 + 2', 'x'), '0');
compareString(derivativeWithoutSimplify('f(y) = 5y + 2', 'x'), '0');
// non-embedded example
var f_of_x = math.parse('f(x) = x + 2');
var newFunc = new OperatorNode('+', 'add', [math.parse('5x'), f_of_x]);
assert.equal(derivativeWithoutSimplify(newFunc, 'x'), '5 * 1 + 1 + 0');
});
it('should take the derivative of a OperatorNodes with ConstantNodes', function() {
compareString(derivativeWithoutSimplify('1 + 2', 'x'), '0');
compareString(derivativeWithoutSimplify('-100^2 + 3*3/2 - 12', 'x'), '0');
});
it('should take the derivative of a OperatorNodes with SymbolNodes', function() {
// d/dx(-4x) = -4*1 = -4
compareString(derivativeWithoutSimplify('-4x', 'x'), '-4 * 1');
// d/dx(+4x) = +4*1 = +4
compareString(derivativeWithoutSimplify('+4x', 'x'), '+4 * 1');
// Linearity of differentiation
// With '+': d/dx(5x + x + 2) = 5*1 + 1 + 0 = 6
compareString(derivativeWithoutSimplify('5x + x + 2', 'x'), '5 * 1 + 1 + 0');
// With '-': d/dx(5x - x - 2) = 5*1 - 1 - 0 = 4
compareString(derivativeWithoutSimplify('5x - x - 2', 'x'), '5 * 1 - 1 - 0');
// d/dx(2*(x + x)) = 2*(1 + 1)
compareString(derivativeWithoutSimplify('2(x + x)', 'x'), '2 * (1 + 1)');
compareString(derivativeWithoutSimplify('(x + x)*2', 'x'), '2 * (1 + 1)');
// Product Rule, d/dx(5x*3x) = 5*(3*1*x + x*3*1) = 30x
compareString(derivativeWithoutSimplify('5x*3x', 'x'), '3 * 5 * 1 * x + 5 x * 3 * 1');
// Basic division, d/dx(7x / 2) = 7 * 1 / 2 = 7 / 2
compareString(derivativeWithoutSimplify('7x / 2', 'x'), '7 * 1 / 2');
// Reciprocal Rule, d/dx(5 / (3x)) = -5 * (3 * 1) / (3 * x) ^ 2 = -5 / 3x^2
compareString(derivativeWithoutSimplify('5 / (3x)', 'x'), '-5 * (3 * 1) / (3 x) ^ 2');
// Quotient rule, d/dx((2x) / (3x + 2)) = ((2*1)(3x + 2) - (2x)(3*1 + 0)) / (3x + 2)^2 = 4 / (3x + 2)^2
compareString(derivativeWithoutSimplify('(2x) / (3x + 2)', 'x'), '((2 * 1) * (3 x + 2) - (2 x) * (3 * 1 + 0)) / (3 x + 2) ^ 2');
// Secret constant; 0^f(x) = 1 (in JS), 1^f(x) = 1, d/dx(1) = 0
compareString(derivativeWithoutSimplify('0^(2^x + x^3 + 2)', 'x'), '0');
compareString(derivativeWithoutSimplify('1^(2^x + x^3 + 2)', 'x'), '0');
// d/dx(10^(2x + 2)) = 10^(2x + 2)*ln(10)*(2*1 + 0)
assert.equal(derivativeWithoutSimplify('10^(2x + 2)', 'x'), '10 ^ (2 x + 2) * log(10) * (2 * 1 + 0)');
// Secret constant, f(x)^0 = 1 -> d/dx(f(x)^0) = 1
compareString(derivativeWithoutSimplify('(x^x^x^x)^0', 'x'), '0');
// Ignore powers of 1, d/dx((x + 2)^1) -> d/dx(x+2) = (1 + 0) = 1
compareString(derivativeWithoutSimplify('(x+2)^1', 'x'), '(1 + 0)');
// Elementary Power Rule, d/dx(2x^2) = 2*2*1*x^(2-1) = 4x
compareString(derivativeWithoutSimplify('2x^2', 'x'), '2 * 2 * 1 * x ^ (2 - 1)');
// Elementary Power Rule, d/dx(2x^-2) = 2*-2*1*x^(-2-1) = -4x^-3
compareString(derivativeWithoutSimplify('2x^-2', 'x'), '2 * -2 * 1 * x ^ (-2 - 1)');
// Functional Power Rule, d/dx((x^3 + x)^(5x + 2)) = (x^3 + x)^(5x + 2) * [(((3*1*x)^(3-1)+1) * ((5x + 2) / (x^3 + x))) + (5*1 + 0)log((x^3 + x))]
// = (x^3 + x)^(5x + 2) * [((3x^2 + 1)*(5x + 2) / (x^3 + x)) + 5log(x^3 + x)]
compareString(derivativeWithoutSimplify('(x^3 + x)^(5x + 2)', 'x'), '(x ^ 3 + x) ^ (5 x + 2) * ((3 * 1 * x ^ (3 - 1) + 1) * (5 x + 2) / (x ^ 3 + x) + (5 * 1 + 0) * log((x ^ 3 + x)))');
});
it('should properly take the derivative of mathematical functions', function() {
compareString(derivativeWithoutSimplify('cbrt(6x)', 'x'), '6 * 1 / (3 * (6 x) ^ (2 / 3))');
compareString(derivativeWithoutSimplify('sqrt(6x)', 'x'), '6 * 1 / (2 * sqrt(6 x))');
compareString(derivativeWithoutSimplify('nthRoot(6x)', 'x'), '6 * 1 / (2 * sqrt(6 x))');
compareString(derivativeWithoutSimplify('nthRoot(6x, 3)', 'x'), '1 / 3 * 6 * 1 * (6 x) ^ (1 / 3 - 1)');
compareString(derivativeWithoutSimplify('nthRoot((6x), (2x))', 'x'), '(6 x) ^ (1 / (2 x)) * ((6 * 1) * 1 / (2 x) / (6 x) + (0 * (2 x) - 1 * (2 * 1)) / (2 x) ^ 2 * log((6 x)))');
compareString(derivativeWithoutSimplify('log((6*x))', 'x'), '(6 * 1) / (6 * x)');
compareString(derivativeWithoutSimplify('log10((6x))', 'x'), '(6 * 1) / ((6 x) * log(10))');
compareString(derivativeWithoutSimplify('log((6x), 10)', 'x'), '(6 * 1) / ((6 x) * log(10))');
// d/dx(log(2x, 3x)) = ((2 * 1) / (2 * x) * log(3 * x) - log(2 * x) * (3 * 1) / (3 * x)) / log(3 * x) ^ 2 = (log(3x) - log(2x)) / (xlog(3x)^2)
compareString(derivativeWithoutSimplify('log((2x), (3x))', 'x'), '((2 * 1) / (2 x) * log((3 x)) - log((2 x)) * (3 * 1) / (3 x)) / log((3 x)) ^ 2');
compareString(derivativeWithoutSimplify('sin(2x)', 'x'), '2 * 1 * cos(2 x)');
compareString(derivativeWithoutSimplify('cos(2x)', 'x'), '2 * 1 * -sin(2 x)');
compareString(derivativeWithoutSimplify('tan(2x)', 'x'), '2 * 1 * sec(2 x) ^ 2');
compareString(derivativeWithoutSimplify('sec(2x)', 'x'), '2 * 1 * sec(2 x) * tan(2 x)');
compareString(derivativeWithoutSimplify('csc(2x)', 'x'), '-(2 * 1) * csc(2 x) * cot(2 x)');
compareString(derivativeWithoutSimplify('cot((2x))', 'x'), '-(2 * 1) * csc((2 x)) ^ 2');
compareString(derivativeWithoutSimplify('asin((2x))', 'x'), '(2 * 1) / sqrt(1 - (2 x) ^ 2)');
compareString(derivativeWithoutSimplify('acos((2x))', 'x'), '-(2 * 1) / sqrt(1 - (2 x) ^ 2)');
compareString(derivativeWithoutSimplify('atan((2x))', 'x'), '(2 * 1) / ((2 x) ^ 2 + 1)');
compareString(derivativeWithoutSimplify('asec((2x))', 'x'), '(2 * 1) / (abs((2 x)) * sqrt((2 x) ^ 2 - 1))');
compareString(derivativeWithoutSimplify('acsc((2x))', 'x'), '-(2 * 1) / (abs((2 x)) * sqrt((2 x) ^ 2 - 1))');
compareString(derivativeWithoutSimplify('acot((2x))', 'x'), '-(2 * 1) / ((2 x) ^ 2 + 1)');
compareString(derivativeWithoutSimplify('sinh(2x)', 'x'), '2 * 1 * cosh(2 x)');
compareString(derivativeWithoutSimplify('cosh(2x)', 'x'), '2 * 1 * sinh(2 x)');
compareString(derivativeWithoutSimplify('tanh(2x)', 'x'), '2 * 1 * sech(2 x) ^ 2');
compareString(derivativeWithoutSimplify('sech(2x)', 'x'), '-(2 * 1) * sech(2 x) * tanh(2 x)');
compareString(derivativeWithoutSimplify('csch(2x)', 'x'), '-(2 * 1) * csch(2 x) * coth(2 x)');
compareString(derivativeWithoutSimplify('coth(2x)', 'x'), '-(2 * 1) * csch(2 x) ^ 2');
compareString(derivativeWithoutSimplify('asinh((2x))', 'x'), '(2 * 1) / sqrt((2 x) ^ 2 + 1)');
compareString(derivativeWithoutSimplify('acosh((2x))', 'x'), '(2 * 1) / sqrt((2 x) ^ 2 - 1)');
compareString(derivativeWithoutSimplify('atanh((2x))', 'x'), '(2 * 1) / (1 - (2 x) ^ 2)');
compareString(derivativeWithoutSimplify('asech((2x))', 'x'), '-(2 * 1) / ((2 x) * sqrt(1 - (2 x) ^ 2))');
compareString(derivativeWithoutSimplify('acsch((2x))', 'x'), '-(2 * 1) / (abs((2 x)) * sqrt((2 x) ^ 2 + 1))');
compareString(derivativeWithoutSimplify('acoth((2x))', 'x'), '-(2 * 1) / (1 - (2 x) ^ 2)');
compareString(derivativeWithoutSimplify('exp(2x)', 'x'), '2 * 1 * exp(2 x)');
});
it('should take the partial derivative of an expression', function() {
compareString(derivativeWithoutSimplify('x + y', 'x'), '1 + 0');
compareString(derivativeWithoutSimplify('x + log(y)*y', 'x'), '1 + 0');
compareString(derivativeWithoutSimplify('x + y + z', 'x'), '1 + 0 + 0');
compareString(derivativeWithoutSimplify('x + log(y)*z', 'x'), '1 + 0');
compareString(derivativeWithoutSimplify('x + log(y)*x', 'x'), '1 + log(y) * 1');
// 2 * 1 * x ^ (2 - 1) + y * 1 + 0 = 2x + y
compareString(derivativeWithoutSimplify('x^2 + x*y + y^2', 'x'), '2 * 1 * x ^ (2 - 1) + y * 1 + 0');
});
it('should function properly even without being called within an eval', function() {
var f = math.parse('2x^3');
// 2*3*1*x^(3-1) = 6x^2
compareString(derivativeWithoutSimplify(f, 'x').toString(), '2 * 3 * 1 * x ^ (3 - 1)');
});
it('should accept string and Node input', function() {
// NOTE: we use `parse` here on purpose to see whether derivative accepts it
compareString(derivative('x^2', 'x'), '2 * x');
compareString(derivative(math.parse('x^2'), 'x'), '2 * x');
compareString(derivative('x^2', math.parse('x')), '2 * x');
compareString(derivative(math.parse('x^2'), math.parse('x')), '2 * x');
});
describe('expression parser', function() {
it('should evaluate a derivative containing string value', function() {
var res = math.eval('derivative("x^2", "x")');
assert.ok(res && res.isNode)
assert.equal(res.toString(), '2 * x');
});
it('should evaluate a derivative containing nodes', function() {
var res = math.eval('derivative(parse("x^2"), parse("x"))');
assert.ok(res && res.isNode)
assert.equal(res.toString(), '2 * x');
});
});
it('should throw error if expressions contain unsupported operators or functions', function() {
assert.throws(function () { derivative('x << 2', 'x'); }, /Error: Operator "<<" not supported by derivative/);
assert.throws(function () { derivative('subset(x)', 'x'); }, /Error: Function "subset" not supported by derivative/);
});
it('should have controlled behavior on arguments errors', function() {
assert.throws(function() {
derivative('sqrt()', 'x');
}, /TypeError: Too few arguments in function sqrt \(expected: number or Complex or BigNumber or Unit or Array or Matrix, index: 0\)/);
assert.throws(function() {
derivative('sqrt(12, 2x)', 'x');
}, /TypeError: Too many arguments in function sqrt \(expected: 1, actual: 2\)/);
});
it('should throw error for incorrect argument types', function() {
assert.throws(function () {
derivative('42', '42');
}, /TypeError: Unexpected type of argument in function derivative \(expected: string or SymbolNode, actual: ConstantNode, index: 1\)/);
assert.throws(function () {
derivative('[1, 2; 3, 4]', 'x');
}, /TypeError: Unexpected type of argument in function constTag \(expected: OperatorNode or ConstantNode or SymbolNode or ParenthesisNode or FunctionNode or FunctionAssignmentNode, actual: ArrayNode, index: 1\)/);
assert.throws(function () {
derivative('x + [1, 2; 3, 4]', 'x');
}, /TypeError: Unexpected type of argument in function constTag \(expected: OperatorNode or ConstantNode or SymbolNode or ParenthesisNode or FunctionNode or FunctionAssignmentNode, actual: ArrayNode, index: 1\)/);
});
it('should throw error if incorrect number of arguments', function() {
assert.throws(function () {
derivative('x + 2');
}, /TypeError: Too few arguments in function derivative \(expected: string or SymbolNode, index: 1\)/);
assert.throws(function () {
derivative('x + 2', 'x', {}, true, 42);
}, /TypeError: Too many arguments in function derivative \(expected: 3, actual: 5\)/);
});
});

View File

@@ -0,0 +1,95 @@
// test simplify
var assert = require('assert');
var math = require('../../../index');
describe('simplify', function() {
function simplifyAndCompare(left, right) {
assert.equal(math.simplify(left).toString(), math.parse(right).toString());
}
function simplifyAndCompareEval (left, right, scope) {
scope = scope || {};
assert.equal(math.simplify(left).eval(scope), math.parse(right).eval(scope));
}
it('should not change the value of the function', function() {
simplifyAndCompareEval('3+2/4+2*8', '39/2');
simplifyAndCompareEval('x+1+x', '2x+1', {x:7});
simplifyAndCompareEval('x+1+2x', '3x+1', {x:7});
simplifyAndCompareEval('x^2+x-3+x^2', '2x^2+x-3', {x:7});
});
it('should simplify rational expressions with no symbols to fraction', function() {
simplifyAndCompare('3*4', '12');
simplifyAndCompare('3+2/4', '7/2');
});
it('should simplify non-rational expressions with no symbols to number', function() {
simplifyAndCompare('3+sin(4)', '2.2431975046920716');
});
it('should collect like terms', function() {
simplifyAndCompare('x+x', '2*x');
simplifyAndCompare('2x+x', '3*x');
simplifyAndCompare('2(x+1)+(x+1)', '3*(x + 1)');
simplifyAndCompare('y*x^2+2*x^2', '(y+2)*x^2');
});
it('should collect separated like terms', function() {
simplifyAndCompare('x+1+x', '2*x+1');
simplifyAndCompare('x^2+x+3+x^2', '2*x^2+x+3');
simplifyAndCompare('x+1+2x', '3*x+1');
simplifyAndCompare('x-1+x', '2*x-1');
simplifyAndCompare('x-1-2x+2', '1-x');
});
it('should collect separated like factors', function() {
simplifyAndCompare('x/2*x', 'x^2/2');
simplifyAndCompare('x*2*x', '2*x^2');
simplifyAndCompare('x*y*-x/(x^2)', '-y');
});
it('should handle non-existing functions like a pro', function() {
simplifyAndCompare('foo(x)', 'foo(x)');
});
describe('expression parser' ,function () {
it('should evaluate simplify containing string value', function() {
var res = math.eval('simplify("2x + 3x")');
assert.ok(res && res.isNode)
assert.equal(res.toString(), '5 * x');
});
it('should evaluate simplify containing nodes', function() {
var res = math.eval('simplify(parse("2x + 3x"))');
assert.ok(res && res.isNode)
assert.equal(res.toString(), '5 * x');
});
it('should compute and simplify derivatives', function() {
var res = math.eval('derivative("5x*3x", "x")');
assert.ok(res && res.isNode)
assert.equal(res.toString(), '30 * x');
});
it('should compute and simplify derivatives (2)', function() {
var scope = {}
math.eval('a = derivative("5x*3x", "x")', scope)
var res = math.eval('simplify(a)', scope);
assert.ok(res && res.isNode)
assert.equal(res.toString(), '30 * x');
});
it.skip('should compute and simplify derivatives (3)', function() {
// TODO: this requires the + operator to support Nodes,
// i.e. math.add(5, math.parse('2')) => return an OperatorNode
var res = math.eval('simplify(5+derivative(5/(3x), x))');
assert.ok(res && res.isNode)
assert.equal(res.toString(), '5 - 15 / (3 * x) ^ 2');
});
});
});

View File

@@ -0,0 +1,121 @@
// test lsolve
var assert = require('assert'),
approx = require('../../../../tools/approx'),
math = require('../../../../index');
describe('lsolve', function () {
it('should solve linear system 4 x 4, arrays', function () {
var m =
[
[1, 0, 0, 0],
[1, 1, 0, 0],
[1, 1, 1, 0],
[1, 1, 1, 1]
];
var b = [1, 2, 3, 4];
var x = math.lsolve(m, b);
approx.deepEqual(x, [1, 1, 1, 1]);
});
it('should solve linear system 4 x 4, array and column array', function () {
var m =
[
[1, 0, 0, 0],
[1, 1, 0, 0],
[1, 1, 1, 0],
[1, 1, 1, 1]
];
var b = [
[1],
[2],
[3],
[4]
];
var x = math.lsolve(m, b);
approx.deepEqual(x, [[1], [1], [1], [1]]);
});
it('should solve linear system 4 x 4, matrices', function () {
var m = math.matrix(
[
[1, 0, 0, 0],
[1, 1, 0, 0],
[1, 1, 1, 0],
[1, 1, 1, 1]
]);
var b = math.matrix([1, 2, 3, 4]);
var x = math.lsolve(m, b);
assert(x instanceof math.type.Matrix);
approx.deepEqual(x, math.matrix([[1], [1], [1], [1]]));
});
it('should solve linear system 4 x 4, sparse matrices', function () {
var m = math.sparse(
[
[1, 0, 0, 0],
[1, 1, 0, 0],
[1, 1, 1, 0],
[1, 1, 1, 1]
]);
var b = math.matrix([[1], [2], [3], [4]], 'sparse');
var x = math.lsolve(m, b);
assert(x instanceof math.type.Matrix);
approx.deepEqual(x, math.matrix([[1], [1], [1], [1]]));
});
it('should solve linear system 4 x 4, matrix and column matrix', function () {
var m = math.matrix(
[
[1, 0, 0, 0],
[1, 1, 0, 0],
[1, 1, 1, 0],
[1, 1, 1, 1]
]);
var b = math.matrix([
[1],
[2],
[3],
[4]
]);
var x = math.lsolve(m, b);
assert(x instanceof math.type.Matrix);
approx.deepEqual(x, math.matrix([[1], [1], [1], [1]]));
});
it('should solve linear system 4 x 4, sparse matrix and column matrix', function () {
var m = math.matrix(
[
[1, 0, 0, 0],
[1, 1, 0, 0],
[1, 1, 1, 0],
[1, 1, 1, 1]
], 'sparse');
var b = math.matrix([
[1],
[2],
[3],
[4]
], 'sparse');
var x = math.lsolve(m, b);
assert(x instanceof math.type.Matrix);
approx.deepEqual(x, math.matrix([[1], [1], [1], [1]]));
});
it('should throw exception when matrix is singular', function () {
assert.throws(function () { math.lsolve([[1, 1], [0, 0]], [1, 1]); }, /Error: Linear system cannot be solved since matrix is singular/);
assert.throws(function () { math.lsolve(math.matrix([[1, 1], [0, 0]], 'dense'), [1, 1]); }, /Error: Linear system cannot be solved since matrix is singular/);
assert.throws(function () { math.lsolve(math.matrix([[1, 1], [0, 0]], 'sparse'), [1, 1]); }, /Error: Linear system cannot be solved since matrix is singular/);
});
});

View File

@@ -0,0 +1,338 @@
// test lusolve
var assert = require('assert'),
approx = require('../../../../tools/approx'),
math = require('../../../../index');
describe('lusolve', function () {
it('should solve linear system 4 x 4, arrays', function () {
var m =
[
[1, 0, 0, 0],
[0, 2, 0, 0],
[0, 0, 3, 0],
[0, 0, 0, 4]
];
var b = [-1, -1, -1, -1];
var x = math.lusolve(m, b);
approx.deepEqual(x, [-1, -0.5, -1/3, -0.25]);
});
it('should solve linear system 4 x 4, array and column array', function () {
var m =
[
[1, 0, 0, 0],
[0, 2, 0, 0],
[0, 0, 3, 0],
[0, 0, 0, 4]
];
var b = [
[-1],
[-1],
[-1],
[-1]
];
var x = math.lusolve(m, b);
approx.deepEqual(x, [[-1], [-0.5], [-1/3], [-0.25]]);
});
it('should solve linear system 4 x 4, matrices', function () {
var m = math.matrix(
[
[1, 0, 0, 0],
[0, 2, 0, 0],
[0, 0, 3, 0],
[0, 0, 0, 4]
]);
var b = math.matrix([-1, -1, -1, -1]);
var x = math.lusolve(m, b);
assert(x instanceof math.type.Matrix);
approx.deepEqual(x, math.matrix([[-1], [-0.5], [-1/3], [-0.25]]));
});
it('should solve linear system 4 x 4, sparse matrices', function () {
var m = math.matrix(
[
[1, 0, 0, 0],
[0, 2, 0, 0],
[0, 0, 3, 0],
[0, 0, 0, 4]
], 'sparse');
var b = math.matrix([[-1], [-1], [-1], [-1]], 'sparse');
var x = math.lusolve(m, b);
assert(x instanceof math.type.Matrix);
approx.deepEqual(x, math.matrix([[-1], [-0.5], [-1/3], [-0.25]]));
});
it('should solve linear system 4 x 4, matrix and column matrix', function () {
var m = math.matrix(
[
[1, 0, 0, 0],
[0, 2, 0, 0],
[0, 0, 3, 0],
[0, 0, 0, 4]
]);
var b = math.matrix([
[-1],
[-1],
[-1],
[-1]
]);
var x = math.lusolve(m, b);
assert(x instanceof math.type.Matrix);
approx.deepEqual(x, math.matrix([[-1], [-0.5], [-1/3], [-0.25]]));
});
it('should solve linear system 4 x 4, sparse matrix and column matrix', function () {
var m = math.matrix(
[
[1, 0, 0, 0],
[0, 2, 0, 0],
[0, 0, 3, 0],
[0, 0, 0, 4]
], 'sparse');
var b = math.matrix([
[-1],
[-1],
[-1],
[-1]
], 'sparse');
var x = math.lusolve(m, b);
assert(x instanceof math.type.Matrix);
approx.deepEqual(x, math.matrix([[-1], [-0.5], [-1/3], [-0.25]]));
});
it('should solve linear system 4 x 4, LUP decomposition (array)', function () {
var m =
[
[1, 0, 0, 0],
[0, 2, 0, 0],
[0, 0, 3, 0],
[0, 0, 0, 4]
];
var lup = math.lup(m);
var x = math.lusolve(lup, [-1, -1, -1, -1]);
approx.deepEqual(x, math.matrix([[-1], [-0.5], [-1/3], [-0.25]]));
var y = math.lusolve(lup, [1, 2, 1, -1]);
approx.deepEqual(y, math.matrix([[1], [1], [1/3], [-0.25]]));
});
it('should solve linear system 4 x 4, LUP decomposition (matrix)', function () {
var m = math.matrix(
[
[1, 0, 0, 0],
[0, 2, 0, 0],
[0, 0, 3, 0],
[0, 0, 0, 4]
]);
var lup = math.lup(m);
var x = math.lusolve(lup, [-1, -1, -1, -1]);
approx.deepEqual(x, math.matrix([[-1], [-0.5], [-1/3], [-0.25]]));
var y = math.lusolve(lup, [1, 2, 1, -1]);
approx.deepEqual(y, math.matrix([[1], [1], [1/3], [-0.25]]));
});
it('should solve linear system 4 x 4, LUP decomposition (sparse matrix)', function () {
var m = math.matrix(
[
[1, 0, 0, 0],
[0, 2, 0, 0],
[0, 0, 3, 0],
[0, 0, 0, 4]
], 'sparse');
var lup = math.lup(m);
var x = math.lusolve(lup, [-1, -1, -1, -1]);
approx.deepEqual(x, math.matrix([[-1], [-0.5], [-1/3], [-0.25]]));
var y = math.lusolve(lup, [1, 2, 1, -1]);
approx.deepEqual(y, math.matrix([[1], [1], [1/3], [-0.25]]));
});
it('should solve linear system 3 x 3, no permutations, arrays', function () {
var m =
[
[2, 1, 1],
[1, 2, -1],
[1, 2, 1]
];
var b = [-2, 4, 2];
var x = math.lusolve(m, b);
approx.deepEqual(x, [[-5/3], [7/3], [-1]]);
});
it('should solve linear system 3 x 3, no permutations, matrix', function () {
var m = math.matrix(
[
[2, 1, 1],
[1, 2, -1],
[1, 2, 1]
]);
var b = [-2, 4, 2];
var x = math.lusolve(m, b);
approx.deepEqual(x, math.matrix([[-5/3], [7/3], [-1]]));
});
it('should solve linear system 3 x 3, no permutations, sparse matrix', function () {
var m = math.matrix(
[
[2, 1, 1],
[1, 2, -1],
[1, 2, 1]
], 'sparse');
var b = [-2, 4, 2];
var x = math.lusolve(m, b);
approx.deepEqual(x, math.matrix([[-5/3], [7/3], [-1]]));
});
it('should solve linear system 3 x 3, permutations, arrays', function () {
var m =
[
[1, 2, -1],
[2, 1, 1],
[1, 2, 1]
];
var b = [4, -2, 2];
var x = math.lusolve(m, b);
approx.deepEqual(x, [[-5/3], [7/3], [-1]]);
});
it('should solve linear system 4 x 4, permutations, matrix - Issue 437', function () {
var m = math.matrix(
[
[ -1, 1, -1, 1],
[ 0, 0, 0, 1],
[ 1, 1, 1, 1],
[ 8, 4, 2, 1]
]);
var b = [0.1, 0.2, 0.15, 0.1];
var x = math.lusolve(m, b);
approx.deepEqual(x, math.matrix([[0.025], [-0.075], [0], [0.2]]));
});
it('should solve linear system 4 x 4, permutations, sparse - Issue 437', function () {
var m = math.sparse(
[
[ -1, 1, -1, 1],
[ 0, 0, 0, 1],
[ 1, 1, 1, 1],
[ 8, 4, 2, 1]
]);
var b = [0.1, 0.2, 0.15, 0.1];
var x = math.lusolve(m, b);
approx.deepEqual(x, math.matrix([[0.025], [-0.075], [0], [0.2]]));
});
it('should solve linear system 3 x 3, permutations, sparse matrix', function () {
var m = math.matrix(
[
[1, 2, -1],
[2, 1, 1],
[1, 2, 1]
], 'sparse');
var b = [4, -2, 2];
var x = math.lusolve(m, b);
approx.deepEqual(x, math.matrix([[-5/3], [7/3], [-1]]));
});
it('should solve linear system 4 x 4, natural ordering (order=0), partial pivoting, sparse matrix', function () {
var m = math.sparse(
[
[4.5, 0, 3.2, 0],
[3.1, 2.9, 0, 0.9],
[0, 1.7, 3, 0],
[3.5, 0.4, 0, 1]
]);
var b = [1.000000, 1.250000, 1.500000, 1.750000];
var x = math.lusolve(m, b, 0, 1);
approx.deepEqual(x, math.matrix([[-0.186372], [-0.131621], [0.574586], [2.454950]]));
});
it('should solve linear system 4 x 4, amd(A+A\') (order=1), partial pivoting, sparse matrix', function () {
var m = math.sparse(
[
[4.5, 0, 3.2, 0],
[3.1, 2.9, 0, 0.9],
[0, 1.7, 3, 0],
[3.5, 0.4, 0, 1]
]);
var b = [1.000000, 1.250000, 1.500000, 1.750000];
var x = math.lusolve(m, b, 1, 1);
approx.deepEqual(x, math.matrix([[-0.186372], [-0.131621], [0.574586], [2.454950]]));
});
it('should solve linear system 4 x 4, amd(A\'*A) (order=2), partial pivoting, sparse matrix', function () {
var m = math.sparse(
[
[4.5, 0, 3.2, 0],
[3.1, 2.9, 0, 0.9],
[0, 1.7, 3, 0],
[3.5, 0.4, 0, 1]
]);
var b = [1.000000, 1.250000, 1.500000, 1.750000];
var x = math.lusolve(m, b, 2, 1);
approx.deepEqual(x, math.matrix([[-0.186372], [-0.131621], [0.574586], [2.454950]]));
});
it('should solve linear system 4 x 4, amd(A\'*A) (order=3), partial pivoting, sparse matrix', function () {
var m = math.sparse(
[
[4.5, 0, 3.2, 0],
[3.1, 2.9, 0, 0.9],
[0, 1.7, 3, 0],
[3.5, 0.4, 0, 1]
]);
var b = [1.000000, 1.250000, 1.500000, 1.750000];
var x = math.lusolve(m, b, 3, 1);
approx.deepEqual(x, math.matrix([[-0.186372], [-0.131621], [0.574586], [2.454950]]));
});
it('should throw exception when matrix is singular', function () {
assert.throws(function () { math.lusolve([[1, 1], [0, 0]], [1, 1]); }, /Error: Linear system cannot be solved since matrix is singular/);
assert.throws(function () { math.lusolve(math.matrix([[1, 1], [0, 0]], 'dense'), [1, 1]); }, /Error: Linear system cannot be solved since matrix is singular/);
assert.throws(function () { math.lusolve(math.matrix([[1, 1], [0, 0]], 'sparse'), [1, 1]); }, /Error: Linear system cannot be solved since matrix is singular/);
});
});

View File

@@ -0,0 +1,121 @@
// test usolve
var assert = require('assert'),
approx = require('../../../../tools/approx'),
math = require('../../../../index');
describe('usolve', function () {
it('should solve linear system 4 x 4, arrays', function () {
var m =
[
[1, 1, 1, 1],
[0, 1, 1, 1],
[0, 0, 1, 1],
[0, 0, 0, 1]
];
var b = [1, 2, 3, 4];
var x = math.usolve(m, b);
approx.deepEqual(x, [-1, -1, -1, 4]);
});
it('should solve linear system 4 x 4, array and column array', function () {
var m =
[
[1, 1, 1, 1],
[0, 1, 1, 1],
[0, 0, 1, 1],
[0, 0, 0, 1]
];
var b = [
[1],
[2],
[3],
[4]
];
var x = math.usolve(m, b);
approx.deepEqual(x, [[-1], [-1], [-1], [4]]);
});
it('should solve linear system 4 x 4, matrices', function () {
var m = math.matrix(
[
[1, 1, 1, 1],
[0, 1, 1, 1],
[0, 0, 1, 1],
[0, 0, 0, 1]
]);
var b = math.matrix([1, 2, 3, 4]);
var x = math.usolve(m, b);
assert(x instanceof math.type.Matrix);
approx.deepEqual(x, math.matrix([[-1], [-1], [-1], [4]]));
});
it('should solve linear system 4 x 4, sparse matrices', function () {
var m = math.sparse(
[
[1, 1, 1, 1],
[0, 1, 1, 1],
[0, 0, 1, 1],
[0, 0, 0, 1]
]);
var b = math.matrix([[1], [2], [3], [4]], 'sparse');
var x = math.usolve(m, b);
assert(x instanceof math.type.Matrix);
approx.deepEqual(x, math.matrix([[-1], [-1], [-1], [4]]));
});
it('should solve linear system 4 x 4, matrix and column matrix', function () {
var m = math.matrix(
[
[1, 1, 1, 1],
[0, 1, 1, 1],
[0, 0, 1, 1],
[0, 0, 0, 1]
]);
var b = math.matrix([
[1],
[2],
[3],
[4]
]);
var x = math.usolve(m, b);
assert(x instanceof math.type.Matrix);
approx.deepEqual(x, math.matrix([[-1], [-1], [-1], [4]]));
});
it('should solve linear system 4 x 4, sparse matrix and column matrix', function () {
var m = math.matrix(
[
[1, 1, 1, 1],
[0, 1, 1, 1],
[0, 0, 1, 1],
[0, 0, 0, 1]
], 'sparse');
var b = math.matrix([
[1],
[2],
[3],
[4]
], 'sparse');
var x = math.usolve(m, b);
assert(x instanceof math.type.Matrix);
approx.deepEqual(x, math.matrix([[-1], [-1], [-1], [4]]));
});
it('should throw exception when matrix is singular', function () {
assert.throws(function () { math.usolve([[1, 1], [0, 0]], [1, 1]); }, /Error: Linear system cannot be solved since matrix is singular/);
assert.throws(function () { math.usolve(math.matrix([[1, 1], [0, 0]], 'dense'), [1, 1]); }, /Error: Linear system cannot be solved since matrix is singular/);
assert.throws(function () { math.usolve(math.matrix([[1, 1], [0, 0]], 'sparse'), [1, 1]); }, /Error: Linear system cannot be solved since matrix is singular/);
});
});

View File

@@ -0,0 +1,98 @@
var assert = require('assert');
var approx = require('../../../../tools/approx');
var market = require('../../../../tools/matrixmarket');
var math = require('../../../../index');
math.import(require('../../../../lib/function/algebra/sparse/cs_amd'));
var cs_amd = math.sparse.cs_amd;
describe('cs_amd', function () {
it('should approximate minimum degree ordering, 48 x 48, natural ordering (order=0), matrix market', function (done) {
// import matrix
market.import('tools/matrices/bcsstk01.tar.gz', ['bcsstk01/bcsstk01.mtx'])
.then(function (matrices) {
// matrix
var m = matrices[0];
// symbolic ordering and analysis, order = 0
var q = cs_amd(0, m);
// verify
assert(q === null);
// indicate test has completed
done();
})
.fail(function (error) {
// indicate test has completed
done(error);
});
});
it('should approximate minimum degree ordering, 48 x 48, amd(A+A\') (order=1), matrix market', function (done) {
// import matrix
market.import('tools/matrices/bcsstk01.tar.gz', ['bcsstk01/bcsstk01.mtx'])
.then(function (matrices) {
// matrix
var m = matrices[0];
// symbolic ordering and analysis, order = 1
var q = cs_amd(1, m);
// verify
approx.deepEqual(q, [10, 28, 29, 24, 0, 11, 30, 6, 23, 22, 40, 46, 42, 18, 4, 16, 34, 5, 9, 39, 21, 44, 45, 43, 15, 25, 26, 27, 3, 33, 41, 19, 20, 2, 38, 32, 1, 14, 8, 13, 37, 31, 12, 36, 17, 47, 35, 7]);
// indicate test has completed
done();
})
.fail(function (error) {
// indicate test has completed
done(error);
});
});
it('should approximate minimum degree ordering, 48 x 48, amd(A\'*A) (order=2), matrix market', function (done) {
// import matrix
market.import('tools/matrices/bcsstk01.tar.gz', ['bcsstk01/bcsstk01.mtx'])
.then(function (matrices) {
// matrix
var m = matrices[0];
// symbolic ordering and analysis, order = 2
var q = cs_amd(2, m, false);
// verify
approx.deepEqual(q, [26, 27, 25, 44, 9, 15, 21, 33, 39, 43, 45, 3, 29, 24, 28, 47, 6, 18, 36, 0, 1, 4, 20, 2, 10, 11, 12, 8, 14, 16, 7, 13, 17, 23, 30, 34, 38, 32, 31, 41, 35, 22, 19, 37, 40, 42, 46, 5]);
// indicate test has completed
done();
})
.fail(function (error) {
// indicate test has completed
done(error);
});
});
it('should approximate minimum degree ordering, 48 x 48, amd(A\'*A) (order=3), matrix market', function (done) {
// import matrix
market.import('tools/matrices/bcsstk01.tar.gz', ['bcsstk01/bcsstk01.mtx'])
.then(function (matrices) {
// matrix
var m = matrices[0];
// symbolic ordering and analysis, order = 3
var q = cs_amd(3, m, false);
// verify
approx.deepEqual(q, [26, 27, 25, 44, 9, 15, 21, 33, 39, 43, 45, 3, 29, 24, 28, 47, 6, 18, 36, 0, 1, 4, 20, 2, 10, 11, 12, 8, 14, 16, 7, 13, 17, 23, 30, 34, 38, 32, 31, 41, 35, 22, 19, 37, 40, 42, 46, 5]);
// indicate test has completed
done();
})
.fail(function (error) {
// indicate test has completed
done(error);
});
});
});

View File

@@ -0,0 +1,211 @@
var assert = require('assert');
var approx = require('../../../../tools/approx');
var market = require('../../../../tools/matrixmarket');
var math = require('../../../../index');
math.import(require('../../../../lib/function/algebra/sparse/cs_permute'));
math.import(require('../../../../lib/function/algebra/sparse/cs_lu'));
math.import(require('../../../../lib/function/algebra/sparse/cs_sqr'));
var cs_permute = math.sparse.cs_permute;
var cs_lu = math.sparse.cs_lu;
var cs_sqr = math.sparse.cs_sqr;
describe('cs_lu', function () {
it('should decompose matrix, 2 x 2, no symbolic ordering and analysis, partial pivoting', function () {
var m = math.sparse([[2, 1], [1, 4]]);
// partial pivoting
var r = cs_lu(m, null, 1);
// L
assert.deepEqual(r.L.valueOf(), [[1, 0], [0.5, 1]]);
// U
assert.deepEqual(r.U.valueOf(), [[2, 1], [0, 3.5]]);
// P
assert.deepEqual(r.pinv, [0, 1]);
// verify
approx.deepEqual(cs_permute(m, r.pinv, null, true), math.multiply(r.L, r.U));
});
it('should decompose matrix, 4 x 4, natural ordering (order=0), partial pivoting', function () {
var m = math.sparse(
[
[4.5, 0, 3.2, 0],
[3.1, 2.9, 0, 0.9],
[0, 1.7, 3, 0],
[3.5, 0.4, 0, 1]
]);
// symbolic ordering and analysis, order = 0
var s = cs_sqr(0, m, false);
// partial pivoting
var r = cs_lu(m, s, 1);
// verify
approx.deepEqual(cs_permute(m, r.pinv, s.q, true).valueOf(), math.multiply(r.L, r.U).valueOf());
});
it('should decompose matrix, 4 x 4, amd(A+A\') (order=1), partial pivoting', function () {
var m = math.sparse(
[
[4.5, 0, 3.2, 0],
[3.1, 2.9, 0, 0.9],
[0, 1.7, 3, 0],
[3.5, 0.4, 0, 1]
]);
// symbolic ordering and analysis, order = 1
var s = cs_sqr(1, m, false);
// partial pivoting
var r = cs_lu(m, s, 1);
// verify
approx.deepEqual(cs_permute(m, r.pinv, s.q, true).valueOf(), math.multiply(r.L, r.U).valueOf());
});
it('should decompose matrix, 4 x 4, amd(A\'*A) (order=2), partial pivoting', function () {
var m = math.sparse(
[
[4.5, 0, 3.2, 0],
[3.1, 2.9, 0, 0.9],
[0, 1.7, 3, 0],
[3.5, 0.4, 0, 1]
]);
// symbolic ordering and analysis, order = 2
var s = cs_sqr(2, m, false);
// partial pivoting
var r = cs_lu(m, s, 1);
// verify
approx.deepEqual(cs_permute(m, r.pinv, s.q, true).valueOf(), math.multiply(r.L, r.U).valueOf());
});
it('should decompose matrix, 4 x 4, amd(A\'*A) (order=3), partial pivoting', function () {
var m = math.sparse(
[
[4.5, 0, 3.2, 0],
[3.1, 2.9, 0, 0.9],
[0, 1.7, 3, 0],
[3.5, 0.4, 0, 1]
]);
// symbolic ordering and analysis, order = 3
var s = cs_sqr(3, m, false);
// partial pivoting
var r = cs_lu(m, s, 1);
// verify
approx.deepEqual(cs_permute(m, r.pinv, s.q, true).valueOf(), math.multiply(r.L, r.U).valueOf());
});
it('should decompose matrix, 48 x 48, natural ordering (order=0), full pivoting, matrix market', function (done) {
// import matrix
market.import('tools/matrices/bcsstk01.tar.gz', ['bcsstk01/bcsstk01.mtx'])
.then(function (matrices) {
// matrix
var m = matrices[0];
// symbolic ordering and analysis, order = 0
var s = cs_sqr(0, m, false);
// full pivoting
var r = cs_lu(m, s, 0.001);
// verify
approx.deepEqual(cs_permute(m, r.pinv, s.q, true).valueOf(), math.multiply(r.L, r.U).valueOf());
// indicate test has completed
done();
})
.fail(function (error) {
// indicate test has completed
done(error);
});
});
it('should decompose matrix, 48 x 48, amd(A+A\') (order=1), full pivoting, matrix market', function (done) {
// import matrix
market.import('tools/matrices/bcsstk01.tar.gz', ['bcsstk01/bcsstk01.mtx'])
.then(function (matrices) {
// matrix
var m = matrices[0];
// symbolic ordering and analysis, order = 1
var s = cs_sqr(1, m, false);
// full pivoting
var r = cs_lu(m, s, 0.001);
// verify
approx.deepEqual(cs_permute(m, r.pinv, s.q, true).valueOf(), math.multiply(r.L, r.U).valueOf());
// indicate test has completed
done();
})
.fail(function (error) {
// indicate test has completed
done(error);
});
});
it('should decompose matrix, 48 x 48, amd(A\'*A) (order=2), full pivoting, matrix market', function (done) {
// import matrix
market.import('tools/matrices/bcsstk01.tar.gz', ['bcsstk01/bcsstk01.mtx'])
.then(function (matrices) {
// matrix
var m = matrices[0];
// symbolic ordering and analysis, order = 2
var s = cs_sqr(2, m, false);
// full pivoting
var r = cs_lu(m, s, 0.001);
// verify
approx.deepEqual(cs_permute(m, r.pinv, s.q, true).valueOf(), math.multiply(r.L, r.U).valueOf());
// indicate test has completed
done();
})
.fail(function (error) {
// indicate test has completed
done(error);
});
});
it('should decompose matrix, 48 x 48, amd(A\'*A) (order=3), full pivoting, matrix market', function (done) {
// import matrix
market.import('tools/matrices/bcsstk01.tar.gz', ['bcsstk01/bcsstk01.mtx'])
.then(function (matrices) {
// matrix
var m = matrices[0];
// symbolic ordering and analysis, order = 3
var s = cs_sqr(3, m, false);
// full pivoting
var r = cs_lu(m, s, 0.001);
// verify
approx.deepEqual(cs_permute(m, r.pinv, s.q, true).valueOf(), math.multiply(r.L, r.U).valueOf());
// indicate test has completed
done();
})
.fail(function (error) {
// indicate test has completed
done(error);
});
});
});

View File

@@ -0,0 +1,104 @@
// test abs
var assert = require('assert');
var math = require('../../../index');
describe('abs', function () {
it('should return the abs value of a boolean', function () {
assert.strictEqual(math.abs(true), 1);
assert.strictEqual(math.abs(false), 0);
});
it('should return the abs value of null', function () {
assert.strictEqual(math.abs(null), 0);
});
it('should return the abs value of a number', function () {
assert.strictEqual(math.abs(-4.2), 4.2);
assert.strictEqual(math.abs(-3.5), 3.5);
assert.strictEqual(math.abs(100), 100);
assert.strictEqual(math.abs(0), 0);
});
it('should return the absolute value of a big number', function () {
assert.deepEqual(math.abs(math.bignumber(-2.3)), math.bignumber(2.3));
assert.deepEqual(math.abs(math.bignumber('5e500')), math.bignumber('5e500'));
assert.deepEqual(math.abs(math.bignumber('-5e500')), math.bignumber('5e500'));
});
it('should return the absolute value of a complex number', function () {
assert.equal(math.abs(math.complex(3, -4)), 5);
assert.equal(math.abs(math.complex(1e200, -4e200)), 4.12310562561766e+200);
});
it('should return the absolute value of a fraction', function () {
var a = math.fraction('-1/3');
assert.equal(math.abs(a).toString(), '0.(3)');
assert.equal(a.toString(), '-0.(3)');
assert.equal(math.abs(math.fraction('1/3')).toString(), '0.(3)');
});
it('should convert a string to a number', function() {
assert.strictEqual(math.abs('-2'), 2);
});
it('should return the absolute value of all elements in an Array', function () {
var a1 = math.abs([1,-2,3]);
assert.ok(Array.isArray(a1));
assert.deepEqual(a1, [1,2,3]);
a1 = math.abs([-2,-1,0,1,2]);
assert.ok(Array.isArray(a1));
assert.deepEqual(a1, [2,1,0,1,2]);
});
it('should return the absolute number of a complex number with zero', function () {
assert.equal(math.abs(math.complex(1, 0)), 1);
assert.equal(math.abs(math.complex(0, 1)), 1);
assert.equal(math.abs(math.complex(0, 0)), 0);
assert.equal(math.abs(math.complex(-1, 0)), 1);
assert.equal(math.abs(math.complex(0, -1)), 1);
});
it('should return the absolute value of all elements in a matrix', function () {
var a1 = math.abs(math.matrix([1,-2,3]));
assert.ok(a1 instanceof math.type.Matrix);
assert.deepEqual(a1.size(), [3]);
assert.deepEqual(a1.valueOf(), [1,2,3]);
a1 = math.abs(math.matrix([-2,-1,0,1,2]));
assert.ok(a1 instanceof math.type.Matrix);
assert.deepEqual(a1.size(), [5]);
assert.deepEqual(a1.valueOf(), [2,1,0,1,2])
});
it('should return the absolute value of a unit', function () {
var u = math.abs(math.unit('5 m'));
assert.equal(u.toString(), '5 m');
u = math.abs(math.unit('-5 m'));
assert.equal(u.toString(), '5 m');
u = math.abs(math.unit('-283.15 degC'));
assert.equal(u.toString(), '-263.15 degC');
u = math.abs(math.unit(math.fraction(2,3), 'm'));
assert.equal(u.toString(), '2/3 m');
u = math.abs(math.unit(math.complex(-4, 3), 'in'));
assert.equal(u.toString(), '5 in');
});
it('should throw an error in case of invalid number of arguments', function() {
assert.throws(function () {math.abs()}, /TypeError: Too few arguments/);
assert.throws(function () {math.abs(1, 2)}, /TypeError: Too many arguments/);
});
it('should throw an error in case of unsupported types', function () {
assert.throws(function () {math.abs(new Date());}, /TypeError: Unexpected type of argument/);
assert.throws(function () {math.abs(undefined);}, /TypeError: Unexpected type of argument/);
});
it('should LaTeX abs', function () {
var expression = math.parse('abs(-1)');
assert.equal(expression.toTex(),'\\left|-1\\right|');
});
});

View File

@@ -0,0 +1,238 @@
// test add
var assert = require('assert');
var approx = require('../../../tools/approx');
var math = require('../../../index');
var add = math.add;
// TODO: make unit tests independent of math
describe('add', function() {
describe('Array', function () {
it('should convert strings and add them element wise', function() {
assert.deepEqual(add('2', ['3', '4']), [5, 6]);
assert.deepEqual(add(['2', '3'], '4'), [6, 7]);
});
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 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.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]]));
});
});
describe('DenseMatrix', function () {
it('should handle strings and matrices element wise', function() {
assert.deepEqual(add('2', math.matrix(['3', '4'])), math.matrix([5, 6]));
assert.deepEqual(add(math.matrix(['2', '3']), '4'), math.matrix([6, 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]]);
});
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]));
});
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 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 sparse and sparse matrices correctly', function() {
var a = math.sparse([[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.sparse([[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]
}));
});
});
describe ('multiple arguments', function () {
it ('should add more than two arguments', function () {
assert.deepEqual(add(2, 3, 4), 9);
assert.deepEqual(add(2, 3, [5,6]), [10,11]);
});
});
});

View File

@@ -0,0 +1,151 @@
// test add
var assert = require('assert');
var approx = require('../../../tools/approx');
var math = require('../../../index');
var BigNumber = require('decimal.js');
var add = math.add;
// TODO: make unit tests independent of math
describe('add', function() {
it('should add two numbers', function() {
assert.equal(add(2, 3), 5);
assert.equal(add(-2, 3), 1);
assert.equal(add(2, -3), -1);
assert.equal(add(-5, -3), -8);
});
it('should add booleans', function() {
assert.equal(add(true, true), 2);
assert.equal(add(true, false), 1);
assert.equal(add(false, true), 1);
assert.equal(add(false, false), 0);
});
it('should add numbers and null', function () {
assert.equal(math.add(null, null), 0);
assert.equal(math.add(null, 1), 1);
assert.equal(math.add(1, null), 1);
});
it('should add mixed numbers and booleans', function() {
assert.equal(add(2, true), 3);
assert.equal(add(2, false), 2);
assert.equal(add(true, 2), 3);
assert.equal(add(false, 2), 2);
});
it('should add BigNumbers', function() {
assert.deepEqual(add(new BigNumber(0.1), new BigNumber(0.2)), new BigNumber(0.3));
assert.deepEqual(add(new BigNumber('2e5001'), new BigNumber('3e5000')), new BigNumber('2.3e5001'));
assert.deepEqual(add(new BigNumber('9999999999999999999'), new BigNumber('1')), new BigNumber('1e19'));
});
it('should add mixed numbers and BigNumbers', 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/);
});
it('should add mixed booleans and BigNumbers', function() {
assert.deepEqual(add(new BigNumber(0.1), true), new BigNumber(1.1));
assert.deepEqual(add(new BigNumber(0.1), false), new BigNumber(0.1));
assert.deepEqual(add(false, new BigNumber(0.2)), new math.type.BigNumber(0.2));
assert.deepEqual(add(true, new BigNumber(0.2)), new math.type.BigNumber(1.2));
});
it('should add mixed complex numbers and BigNumbers', function() {
assert.deepEqual(add(math.complex(3, -4), new BigNumber(2)), math.complex(5, -4));
assert.deepEqual(add(new BigNumber(2), math.complex(3, -4)), math.complex(5, -4));
});
it('should add two complex numbers', function() {
assert.equal(add(math.complex(3, -4), math.complex(8, 2)), '11 - 2i');
assert.equal(add(math.complex(3, -4), 10), '13 - 4i');
assert.equal(add(10, math.complex(3, -4)), '13 - 4i');
});
it('should add two fractions', function() {
var a = math.fraction(1,3);
assert.equal(add(a, math.fraction(1,6)).toString(), '0.5');
assert.equal(a.toString(), '0.(3)');
assert.equal(add(math.fraction(1,5), math.fraction(2,5)).toString(), '0.6');
assert.equal(add(math.fraction(1), math.fraction(1,3)).toString(), '1.(3)');
});
it('should add mixed fractions and numbers', function() {
assert.deepEqual(add(1, math.fraction(1,3)), math.fraction(4,3));
assert.deepEqual(add(math.fraction(1,3), 1), math.fraction(4,3));
});
it('should throw an error when converting a number with 15+ digits to fraction', function() {
assert.throws(function () {
add(math.pi, math.fraction(1,3))
}, /Cannot implicitly convert a number with >15 significant digits to Fraction/);
});
it('should add strings to numbers', function() {
assert.strictEqual(add('2', '3'), 5);
assert.strictEqual(add(2, '3'), 5);
assert.strictEqual(add('2', 3), 5);
});
it('should add strings to BigNumbers', function() {
assert.deepEqual(add('2', math.bignumber(3)), math.bignumber(5));
assert.deepEqual(add(math.bignumber(3), '2'), math.bignumber(5));
assert.throws(function () { add('foo', math.bignumber(3)) }, /Error: Cannot convert "foo" to BigNumber/)
});
it('should add strings to Fractions', function() {
assert.deepEqual(add('2', math.fraction(3)), math.fraction(5));
assert.deepEqual(add(math.fraction(3), '2'), math.fraction(5));
assert.throws(function () { add('foo', math.fraction(3)) }, /Error: Cannot convert "foo" to Fraction/)
});
it('should add strings to Complex numbers', function() {
assert.deepEqual(add('2', math.complex(0, 3)), math.complex(2, 3));
assert.deepEqual(add(math.complex(0, 3), '2'), math.complex(2, 3));
assert.throws(function () { add('foo', math.complex(0, 3)) }, /Error: Cannot convert "foo" to Complex/)
});
it('should add two measures of the same unit', function() {
approx.deepEqual(add(math.unit(5, 'km'), math.unit(100, 'mile')), math.unit(165.93, 'km'));
approx.deepEqual(add(math.unit(math.fraction(1,3), 'm'), math.unit(math.fraction(1,3), 'm')).toString(), '2/3 m');
approx.deepEqual(add(math.unit(math.complex(-3, 2), 'g'), math.unit(math.complex(5, -6), 'g')).toString(), '(2 - 4i) g');
});
it('should throw an error for two measures of different units', function() {
assert.throws(function () {
add(math.unit(5, 'km'), math.unit(100, 'gram'));
});
});
it('should throw an error when one of the two units has undefined value', function() {
assert.throws(function () {
add(math.unit('km'), math.unit('5gram'));
}, /Parameter x contains a unit with undefined value/);
assert.throws(function () {
add(math.unit('5 km'), math.unit('gram'));
}, /Parameter y contains a unit with undefined value/);
});
it('should throw an error in case of a unit and non-unit argument', function() {
assert.throws(function () {add(math.unit('5cm'), 2);}, /TypeError: Unexpected type of argument in function add/);
assert.throws(function () {add(math.unit('5cm'), new Date());}, /TypeError: Unexpected type of argument in function add/);
assert.throws(function () {add(new Date(), math.unit('5cm'));}, /TypeError: Unexpected type of argument in function add/);
});
it('should throw an error in case of invalid number of arguments', function() {
assert.throws(function () {add(1);}, /TypeError: Too few arguments/);
});
it('should LaTeX add', function () {
var expression = math.parse('add(1,2)');
assert.equal(expression.toTex(), '\\left(1+2\\right)');
});
});

View File

@@ -0,0 +1,136 @@
// test cbrt
var assert = require('assert');
var approx = require('../../../tools/approx');
var error = require('../../../lib/error/index');
var math = require('../../../index');
var cbrt = math.cbrt;
var bignumber = math.bignumber;
var complex = math.complex;
describe('cbrt', function() {
it('should return the cubic root of a boolean', function () {
assert.equal(cbrt(true), 1);
assert.equal(cbrt(false), 0);
});
it('should return the cubic root of null', function () {
assert.equal(cbrt(null), 0);
});
it('should return the cubic root of a positive number', function() {
assert.equal(cbrt(0), 0);
assert.equal(cbrt(1), 1);
assert.equal(cbrt(8), 2);
assert.equal(cbrt(27), 3);
assert.equal(cbrt(64), 4);
assert.equal(cbrt(125), 5);
approx.equal(cbrt(10), 2.1544346900318834);
});
it('should return the cubic root of a negative number', function() {
assert.strictEqual(cbrt(-8), -2);
assert.strictEqual(cbrt(-64), -4);
});
it('should return the cubic root of infinity', function() {
assert.strictEqual(cbrt(Infinity), Infinity);
assert.strictEqual(cbrt(-Infinity), -Infinity);
});
it('should return all cubic roots of a number', function() {
approx.deepEqual(cbrt(8, true), math.matrix([
complex('2'),
complex('-1 + 1.7321i'),
complex('-1 - 1.7321i')
]));
approx.deepEqual(cbrt(-8, true), math.matrix([
complex('1 + 1.7321i'),
complex('-2'),
complex('1 - 1.7321i')
]));
});
it('should return the cubic root of a positive bignumber', function() {
assert.deepEqual(cbrt(bignumber(0)), bignumber(0));
assert.deepEqual(cbrt(bignumber(1)), bignumber(1));
assert.deepEqual(cbrt(bignumber(8)), bignumber(2));
assert.deepEqual(cbrt(bignumber(27)), bignumber(3));
assert.deepEqual(cbrt(bignumber(64)), bignumber(4));
assert.deepEqual(cbrt(bignumber(125)), bignumber(5));
assert.deepEqual(cbrt(bignumber(10)), bignumber('2.154434690031883721759293566519350495259344942192108582489235506'));
});
it('should return the cubic root of a negative bignumber', function() {
assert.deepEqual(cbrt(bignumber(-8)), bignumber(-2));
assert.deepEqual(cbrt(bignumber(-64)), bignumber(-4));
});
it('should return the cubic root of a complex number', function() {
approx.deepEqual(cbrt(complex('2 + 3i')), complex('1.451856618352664928164697 + 0.493403534104004716735578i'));
approx.deepEqual(cbrt(complex('-2 + 3i')), complex('1.15322830402742 + 1.01064294709397i'));
approx.deepEqual(cbrt(complex('8i')), complex('1.73205080756888 + i'));
});
it('should return all three roots of a complex number', function() {
approx.deepEqual(cbrt(complex('2 + 3i'), true), math.matrix([
complex('1.4519 + 0.4934i'),
complex('-1.1532 + 1.0106i'),
complex('-0.2986 - 1.5040i')
]));
approx.deepEqual(cbrt(complex('8i'), true), math.matrix([
complex(' 1.7321 + i'),
complex('-1.7321 + i'),
complex('-2i')
]));
math.config({matrix: 'Array'});
approx.deepEqual(cbrt(complex('8i'), true), [
complex(' 1.7321 + i'),
complex('-1.7321 + i'),
complex('-2i')
]);
math.config({matrix: 'Matrix'});
});
it('should return the cubic root of a unit', function() {
assert.equal(cbrt(math.unit('27 m^3')).toString(), math.unit('3 m').toString());
assert.equal(cbrt(math.unit('-27 m^3')).toString(), math.unit('-3 m').toString());
assert(cbrt(math.unit(math.bignumber(27), 'm^3')).value.isBigNumber);
assert.deepEqual(cbrt(math.unit(math.bignumber(27), 'm^3')).value, math.bignumber(3));
assert(cbrt(math.unit(math.bignumber(-27), 'm^3')).value.isBigNumber);
assert.deepEqual(cbrt(math.unit(math.bignumber(-27), 'm^3')).value, math.bignumber(-3));
assert(cbrt(math.unit(math.complex(-46, 9), 's^3')).value.isComplex);
approx.deepEqual(cbrt(math.unit(math.complex(-46, 9), 's^3')).value, math.complex(2, 3));
});
it('should throw an error when used with a string', function() {
assert.throws(function () {
cbrt('a string');
});
});
it('should return the cubic root of each element of a matrix', function() {
assert.deepEqual(cbrt([8,27,64,125]), [2,3,4,5]);
assert.deepEqual(cbrt([[8,27],[64,125]]), [[2,3],[4,5]]);
assert.deepEqual(cbrt(math.matrix([[8,27],[64,125]])), math.matrix([[2,3],[4,5]]));
});
it('should throw an error in case of invalid number of arguments', function() {
assert.throws(function () {cbrt()}, /TypeError: Too few arguments/);
assert.throws(function () {cbrt(1, true, 2)}, /TypeError: Too many arguments/);
});
it('should LaTeX cbrt', function () {
var expression = math.parse('cbrt(2)');
assert.equal(expression.toTex(), '\\sqrt[3]{2}');
});
});

View File

@@ -0,0 +1,98 @@
// test ceil
var assert = require('assert');
var approx = require('../../../tools/approx');
var math = require('../../../index');
var bignumber = math.bignumber;
var complex = math.complex;
var fraction = math.fraction;
var matrix = math.matrix;
var unit = math.unit;
var range = math.range;
var ceil = math.ceil;
describe('ceil', function() {
it('should return the ceil of a boolean', function () {
assert.equal(ceil(true), 1);
assert.equal(ceil(false), 0);
});
it('should return the ceil of null', function () {
assert.equal(math.ceil(null), 0);
});
it('should return the ceil of a number', function() {
approx.equal(ceil(0), 0);
approx.equal(ceil(1), 1);
approx.equal(ceil(1.3), 2);
approx.equal(ceil(1.8), 2);
approx.equal(ceil(2), 2);
approx.equal(ceil(-1), -1);
approx.equal(ceil(-1.3), -1);
approx.equal(ceil(-1.8), -1);
approx.equal(ceil(-2), -2);
approx.equal(ceil(-2.1), -2);
approx.equal(ceil(math.pi), 4);
});
it('should return the ceil of a big number', function () {
assert.deepEqual(ceil(bignumber(0)), bignumber(0));
assert.deepEqual(ceil(bignumber(1)), bignumber(1));
assert.deepEqual(ceil(bignumber(1.3)), bignumber(2));
assert.deepEqual(ceil(bignumber(1.8)), bignumber(2));
assert.deepEqual(ceil(bignumber(2)), bignumber(2));
assert.deepEqual(ceil(bignumber(-1)), bignumber(-1));
assert.deepEqual(ceil(bignumber(-1.3)), bignumber(-1));
assert.deepEqual(ceil(bignumber(-1.8)), bignumber(-1));
assert.deepEqual(ceil(bignumber(-2)), bignumber(-2));
assert.deepEqual(ceil(bignumber(-2.1)), bignumber(-2));
});
it('should return the ceil of real and imag part of a complex', function() {
approx.deepEqual(ceil(complex(0, 0)), complex(0, 0));
approx.deepEqual(ceil(complex(1.3, 1.8)), complex(2, 2));
approx.deepEqual(ceil(math.i), complex(0, 1));
approx.deepEqual(ceil(complex(-1.3, -1.8)), complex(-1, -1));
});
it('should return the ceil of a number', function() {
var a = fraction('2/3');
assert(ceil(a) instanceof math.type.Fraction);
assert.equal(a.toString(), '0.(6)');
assert.equal(ceil(fraction(0)).toString(), '0');
assert.equal(ceil(fraction(1)), '1');
assert.equal(ceil(fraction(1.3)).toString(), '2');
assert.equal(ceil(fraction(1.8)).toString(), '2');
assert.equal(ceil(fraction(2)).toString(), '2');
assert.equal(ceil(fraction(-1)).toString(), '-1');
assert.equal(ceil(fraction(-1.3)).toString(), '-1');
assert.equal(ceil(fraction(-1.8)).toString(), '-1');
assert.equal(ceil(fraction(-2)).toString(), '-2');
assert.equal(ceil(fraction(-2.1)).toString(), '-2');
});
it('should throw an error for units', function() {
assert.throws(function () {ceil(unit('5cm'))}, TypeError, 'Function ceil(unit) not supported');
});
it('should convert a string to a number', function() {
assert.strictEqual(ceil('1.8'), 2);
});
it('should ceil each element in a matrix, array or range', function() {
approx.deepEqual(ceil([1.2, 3.4, 5.6, 7.8, 10.0]), [2, 4, 6, 8, 10]);
approx.deepEqual(ceil(matrix([1.2, 3.4, 5.6, 7.8, 10.0])), matrix([2, 4, 6, 8, 10]));
});
it('should throw an error in case of invalid number of arguments', function() {
assert.throws(function () {ceil()}, /TypeError: Too few arguments/);
assert.throws(function () {ceil(1, 2)}, /TypeError: Too many arguments/);
});
it('should LaTeX ceil', function () {
var expression = math.parse('ceil(0.5)');
assert.equal(expression.toTex(), '\\left\\lceil0.5\\right\\rceil');
});
});

View File

@@ -0,0 +1,74 @@
// test cube
var assert = require('assert');
var math = require('../../../index');
var unit = math.unit;
var bignumber = math.bignumber;
var fraction = math.fraction;
var matrix = math.matrix;
var range = math.range;
var cube = math.cube;
describe('cube', function() {
it('should return the cube of a boolean', function () {
assert.equal(cube(true), 1);
assert.equal(cube(false), 0);
});
it('should return the cube of null', function () {
assert.equal(math.ceil(null), 0);
});
it('should return the cube of a number', function() {
assert.equal(cube(4), 64);
assert.equal(cube(-2), -8);
assert.equal(cube(0), 0);
});
it('should return the cube of a big number', function() {
assert.deepEqual(cube(bignumber(4)), bignumber(64));
assert.deepEqual(cube(bignumber(-2)), bignumber(-8));
assert.deepEqual(cube(bignumber(0)), bignumber(0));
});
it('should return the cube of a fraction', function() {
var a = fraction(0.5);
assert(cube(a) instanceof math.type.Fraction);
assert.equal(cube(a).toString(), '0.125');
assert.equal(a.toString(), '0.5');
});
it('should return the cube of a complex number', function() {
assert.deepEqual(cube(math.complex('2i')), math.complex('-8i'));
assert.deepEqual(cube(math.complex('2+3i')), math.complex('-46+9i'));
assert.deepEqual(cube(math.complex('2')), math.complex('8'));
});
it('should return the cube of a unit', function() {
assert.equal(cube(math.unit('4 cm')).toString(), '64 cm^3');
assert.equal(cube(math.unit('-2 cm')).toString(), '-8 cm^3');
assert.equal(cube(math.unit('0 cm')).toString(), '0 cm^3');
});
it('should throw an error with strings', function() {
assert.throws(function () {cube('text')});
});
it('should throw an error if there\'s wrong number of args', function() {
assert.throws(function () {cube()}, /TypeError: Too few arguments/);
assert.throws(function () {cube(1, 2)}, /TypeError: Too many arguments/);
});
it('should cube each element in a matrix, array or range', function() {
// array, matrix, range
// arrays are evaluated element wise
assert.deepEqual(cube([2,3,4,5]), [8,27,64,125]);
assert.deepEqual(cube(matrix([2,3,4,5])), matrix([8,27,64,125]));
assert.deepEqual(cube(matrix([[1,2],[3,4]])), matrix([[1,8],[27,64]]));
});
it('should LaTeX cube', function () {
var expression = math.parse('cube(2)');
assert.equal(expression.toTex(), '\\left(2\\right)^3');
});
});

View File

@@ -0,0 +1,216 @@
// test divide
var assert = require('assert');
var math = require('../../../index');
var error = require('../../../lib/error/index');
var approx = require('../../../tools/approx');
var divide = math.divide;
var bignumber = math.bignumber;
var complex = math.complex;
describe('divide', function() {
it('should divide two numbers', function() {
assert.equal(divide(4, 2), 2);
assert.equal(divide(-4, 2), -2);
assert.equal(divide(4, -2), -2);
assert.equal(divide(-4, -2), 2);
assert.equal(divide(4, 0), Infinity);
assert.equal(divide(-4, 0), -Infinity);
assert.equal(divide(0, -5), 0);
assert.ok(isNaN(divide(0, 0)));
});
it('should divide booleans', function() {
assert.equal(divide(true, true), 1);
assert.equal(divide(true, false), Infinity);
assert.equal(divide(false, true), 0);
assert.ok(isNaN(divide(false, false)));
});
it('should divide numbers and null', function () {
assert.equal(divide(1, null), Infinity);
assert.equal(divide(null, 1), 0);
assert(isNaN(divide(null, null)));
});
it('should divide mixed numbers and booleans', function() {
assert.equal(divide(2, true), 2);
assert.equal(divide(2, false), Infinity);
approx.equal(divide(true, 2), 0.5);
assert.equal(divide(false, 2), 0);
});
it('should divide bignumbers', function() {
assert.deepEqual(divide(bignumber(0.3), bignumber(0.2)), bignumber(1.5));
assert.deepEqual(divide(bignumber('2.6e5000'), bignumber('2')), bignumber('1.3e5000'));
});
it('should divide mixed numbers and bignumbers', function() {
assert.deepEqual(divide(bignumber(0.3), 0.2), bignumber(1.5));
assert.deepEqual(divide(0.3, bignumber(0.2)), bignumber(1.5));
assert.deepEqual(divide(bignumber('2.6e5000'), 2), bignumber('1.3e5000'));
assert.throws(function () {divide(1/3, bignumber(2))}, /Cannot implicitly convert a number with >15 significant digits to BigNumber/);
assert.throws(function () {divide(bignumber(1), 1/3)}, /Cannot implicitly convert a number with >15 significant digits to BigNumber/);
});
it('should divide mixed booleans and bignumbers', function() {
assert.deepEqual(divide(bignumber(0.3), true), bignumber(0.3));
assert.deepEqual(divide(bignumber(0.3), false).toString(), 'Infinity');
assert.deepEqual(divide(false, bignumber('2')), bignumber(0));
assert.deepEqual(divide(true, bignumber('2')), bignumber(0.5));
});
it('should divide two complex numbers', function() {
approx.deepEqual(divide(complex('2+3i'), 2), complex('1+1.5i'));
approx.deepEqual(divide(complex('2+3i'), complex('4i')), complex('0.75 - 0.5i'));
approx.deepEqual(divide(complex('2i'), complex('4i')), complex('0.5'));
approx.deepEqual(divide(4, complex('1+2i')), complex('0.8 - 1.6i'));
approx.deepEqual(divide(math.i, 0), complex(0, Infinity));
approx.deepEqual(divide(complex(0,1), 0), complex(0, Infinity));
approx.deepEqual(divide(complex(1,0), 0), complex(Infinity, 0));
approx.deepEqual(divide(complex(0,1), complex(0,0)), complex(0, Infinity));
approx.deepEqual(divide(complex(1,1), complex(0,0)), complex(Infinity, Infinity));
approx.deepEqual(divide(complex(1,-1), complex(0,0)), complex(Infinity, -Infinity));
approx.deepEqual(divide(complex(-1,1), complex(0,0)), complex(-Infinity, Infinity));
approx.deepEqual(divide(complex(1,1), complex(0,1)), complex(1, -1));
approx.deepEqual(divide(complex(1,1), complex(1,0)), complex(1, 1));
approx.deepEqual(divide(complex(2, 3), complex(4, 5)), complex('0.5609756097560976 + 0.0487804878048781i'));
approx.deepEqual(divide(complex(2, 3), complex(4, -5)), complex('-0.170731707317073 + 0.536585365853659i'));
approx.deepEqual(divide(complex(2, 3), complex(-4, 5)), complex('0.170731707317073 - 0.536585365853659i'));
approx.deepEqual(divide(complex(2, 3), complex(-4, -5)), complex('-0.5609756097560976 - 0.0487804878048781i'));
approx.deepEqual(divide(complex(2, -3), complex(4, 5)), complex('-0.170731707317073 - 0.536585365853659i'));
approx.deepEqual(divide(complex(2, -3), complex(4, -5)), complex('0.5609756097560976 - 0.0487804878048781i'));
approx.deepEqual(divide(complex(2, -3), complex(-4, 5)), complex('-0.5609756097560976 + 0.0487804878048781i'));
approx.deepEqual(divide(complex(2, -3), complex(-4, -5)), complex('0.170731707317073 + 0.536585365853659i'));
approx.deepEqual(divide(complex(-2, 3), complex(4, 5)), complex('0.170731707317073 + 0.536585365853659i'));
approx.deepEqual(divide(complex(-2, 3), complex(4, -5)), complex('-0.5609756097560976 + 0.0487804878048781i'));
approx.deepEqual(divide(complex(-2, 3), complex(-4, 5)), complex('0.5609756097560976 - 0.0487804878048781i'));
approx.deepEqual(divide(complex(-2, 3), complex(-4, -5)), complex('-0.170731707317073 - 0.536585365853659i'));
approx.deepEqual(divide(complex(-2, -3), complex(4, 5)), complex('-0.5609756097560976 - 0.0487804878048781i'));
approx.deepEqual(divide(complex(-2, -3), complex(4, -5)), complex('0.170731707317073 - 0.536585365853659i'));
approx.deepEqual(divide(complex(-2, -3), complex(-4, 5)), complex('-0.170731707317073 + 0.536585365853659i'));
approx.deepEqual(divide(complex(-2, -3), complex(-4, -5)), complex('0.5609756097560976 + 0.0487804878048781i'));
});
it('should divide mixed complex numbers and numbers', function() {
assert.deepEqual(divide(math.complex(6, -4), 2), math.complex(3, -2));
assert.deepEqual(divide(1, math.complex(2, 4)), math.complex(0.1, -0.2));
});
it('should divide mixed complex numbers and bignumbers', function() {
assert.deepEqual(divide(math.complex(6, -4), bignumber(2)), math.complex(3, -2));
assert.deepEqual(divide(bignumber(1), math.complex(2, 4)), math.complex(0.1, -0.2));
});
it('should divide two fractions', function() {
var a = math.fraction(1,4);
assert.equal(divide(a, math.fraction(1,2)).toString(), '0.5');
assert.equal(a.toString(), '0.25');
});
it('should divide mixed fractions and numbers', function() {
assert.deepEqual(divide(1, math.fraction(3)), math.fraction(1,3));
assert.deepEqual(divide(math.fraction(1), 3), math.fraction(1,3));
});
it('should divide units by a number', function() {
assert.equal(divide(math.unit('5 m'), 10).toString(), '0.5 m');
});
it('should divide valueless units by a number', function() {
assert.equal(divide(math.unit('m'), 2).toString(), '0.5 m');
});
it('should divide a number by a unit', function() {
assert.equal(divide(20, math.unit('4 N s')).toString(), '5 N^-1 s^-1');
assert.equal(divide(4, math.unit('W')).toString(), '4 W^-1');
assert.equal(divide(2.5, math.unit('1.25 mm')).toString(), '2 mm^-1');
assert.equal(divide(10, math.unit('4 mg/s')).toString(), '2.5 s / mg');
assert.equal(divide(10, math.unit(math.fraction(4), 'mg/s')).toString(), '5/2 s / mg');
approx.equal(math.format(divide(10, math.unit(math.complex(1,2), 'm/s')), 14), '(2 - 4i) s / m');
});
it('should divide two units', function() {
assert.equal(divide(math.unit('75 mi/h'), math.unit('40 mi/gal')).to('gal/minute').toString(), '0.03125 gal / minute');
var a = math.unit(math.fraction(75), 'mi/h');
var b = math.unit(math.fraction(40), 'mi/gal');
assert.equal(divide(a, b).to('gal/minute').toString(), '1/32 gal / minute');
var c = math.unit(math.complex(21, 1), 'kg');
var d = math.unit(math.complex(2, -3), 's');
assert.equal(divide(c, d).toString(), "(3 + 5.000000000000001i) kg / s");
});
it('should divide one valued unit by a valueless unit and vice-versa', function() {
assert.equal(divide(math.unit('4 gal'), math.unit('L')).toString(), '15.141648');
assert.equal(divide(math.unit('gal'), math.unit('4 L')).toString(), '0.946353');
assert.equal(divide(math.unit('inch'), math.unit(math.fraction(1), 'cm')).toFraction(), '127/50');
});
it('should divide (but not simplify) two valueless units', function() {
assert.equal(divide(math.unit('gal'), math.unit('L')).toString(), 'gal / L');
});
it('should divide units by a big number', function() {
assert.equal(divide(math.unit('5 m'), bignumber(10)).toString(), '0.5 m');
});
it('should divide each elements in a matrix by a number', function() {
assert.deepEqual(divide([2,4,6], 2), [1,2,3]);
a = math.matrix([[1,2],[3,4]]);
assert.deepEqual(divide(a, 2), math.matrix([[0.5,1],[1.5,2]]));
assert.deepEqual(divide(a.valueOf(), 2), [[0.5,1],[1.5,2]]);
assert.deepEqual(divide([], 2), []);
assert.deepEqual(divide([], 2), []);
});
it('should divide 1 over a matrix (matrix inverse)', function() {
approx.deepEqual(divide(1, [
[ 1, 4, 7],
[ 3, 0, 5],
[-1, 9, 11]
]), [
[ 5.625, -2.375, -2.5],
[ 4.75, -2.25, -2],
[-3.375, 1.625, 1.5]
]);
});
it('should perform matrix division', function() {
a = math.matrix([[1,2],[3,4]]);
b = math.matrix([[5,6],[7,8]]);
assert.deepEqual(divide(a, b), math.matrix([[3,-2], [2,-1]]));
});
it('should divide a matrix by a matrix containing a scalar', function() {
assert.throws(function () {divide(a, [[1]])});
});
/*
// These are supported now --ericman314
it('should throw an error if dividing a number by a unit', function() {
assert.throws(function () {divide(10, math.unit('5 m')).toString()});
});
it('should throw an error if dividing a unit by a non-number', function() {
assert.throws(function () {divide(math.unit('5 m'), math.unit('5cm')).toString()});
});
*/
it('should throw an error if there\'s wrong number of arguments', function() {
assert.throws(function () {divide(2,3,4); });
assert.throws(function () {divide(2); });
});
it('should LaTeX divide', function () {
var expression = math.parse('divide(1,2)');
assert.equal(expression.toTex(), '\\frac{1}{2}');
});
});

View File

@@ -0,0 +1,178 @@
// test dotDivide (element-wise divide)
var assert = require('assert'),
math = require('../../../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);
assert.equal(dotDivide(4, -2), -2);
assert.equal(dotDivide(-4, -2), 2);
assert.equal(dotDivide(4, 0), Infinity);
assert.equal(dotDivide(0, -5), 0);
assert.ok(isNaN(dotDivide(0, 0)));
});
it('should divide booleans', function() {
assert.equal(dotDivide(true, true), 1);
assert.equal(dotDivide(true, false), Infinity);
assert.equal(dotDivide(false, true), 0);
assert.ok(isNaN(dotDivide(false, false)));
});
it('should add mixed numbers and booleans', function() {
assert.equal(dotDivide(2, true), 2);
assert.equal(dotDivide(2, false), Infinity);
approx.equal(dotDivide(true, 2), 0.5);
assert.equal(dotDivide(false, 2), 0);
});
it('should divide numbers and null', function () {
assert.equal(dotDivide(1, null), Infinity);
assert.equal(dotDivide(null, 1), 0);
});
it('should throw an error if there\'s wrong number of arguments', function() {
assert.throws(function () {dotDivide(2,3,4); });
assert.throws(function () {dotDivide(2); });
});
it('should divide two complex numbers', function() {
approx.deepEqual(dotDivide(complex('2+3i'), 2), complex('1+1.5i'));
approx.deepEqual(dotDivide(complex('2+3i'), complex('4i')), complex('0.75 - 0.5i'));
approx.deepEqual(dotDivide(complex('2i'), complex('4i')), 0.5);
approx.deepEqual(dotDivide(4, complex('1+2i')), complex('0.8 - 1.6i'));
});
it('should divide a unit by a number', function() {
assert.equal(dotDivide(math.unit('5 m'), 10).toString(), '0.5 m');
});
it('should divide a number by a unit', function() {
assert.equal(dotDivide(10, math.unit('5 m')).toString(), '2 m^-1');
});
/*
// This is supported not --ericman314
it('should throw an error if dividing a number by a unit', function() {
assert.throws(function () {dotDivide(10, math.unit('5 m')).toString();});
});
*/
describe('Array', function () {
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 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 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)');
});
});

View File

@@ -0,0 +1,189 @@
// test dotMultiply (element-wise multiply)
var assert = require('assert'),
math = require('../../../index'),
approx = require('../../../tools/approx'),
error = require('../../../lib/error/index'),
dotMultiply = math.dotMultiply,
divide = math.divide,
matrix = math.matrix,
sparse = math.sparse,
complex = math.complex,
range = math.range,
i = math.i,
unit = math.unit;
describe('dotMultiply', function() {
it('should multiply 2 numbers', function() {
// number
approx.equal(dotMultiply(2, 3), 6);
approx.equal(dotMultiply(-2, 3), -6);
approx.equal(dotMultiply(-2, -3), 6);
approx.equal(dotMultiply(5, 0), 0);
approx.equal(dotMultiply(0, 5), 0);
});
it('should multiply booleans', function() {
assert.equal(dotMultiply(true, true), 1);
assert.equal(dotMultiply(true, false), 0);
assert.equal(dotMultiply(false, true), 0);
assert.equal(dotMultiply(false, false), 0);
});
it('should multiply mixed numbers and booleans', function() {
assert.equal(dotMultiply(2, true), 2);
assert.equal(dotMultiply(2, false), 0);
assert.equal(dotMultiply(true, 2), 2);
assert.equal(dotMultiply(false, 2), 0);
});
it('should multiply numbers and null', function () {
assert.equal(dotMultiply(1, null), 0);
assert.equal(dotMultiply(null, 1), 0);
});
it('should multiply 2 complex numbers', function() {
// complex
approx.deepEqual(dotMultiply(complex(2, 3), 2), complex(4, 6));
approx.deepEqual(dotMultiply(complex(2, -3), 2), complex(4, -6));
approx.deepEqual(dotMultiply(complex(0, 1), complex(2, 3)), complex(-3, 2));
approx.deepEqual(dotMultiply(complex(2, 3), complex(2, 3)), complex(-5, 12));
approx.deepEqual(dotMultiply(2, complex(2, 3)), complex(4, 6));
approx.deepEqual(divide(complex(-5, 12), complex(2, 3)), complex(2, 3));
});
it('should multiply a unit by a number', function() {
// unit
assert.equal(dotMultiply(2, unit('5 mm')).toString(), '10 mm');
assert.equal(dotMultiply(2, unit('5 mm')).toString(), '10 mm');
assert.equal(dotMultiply(unit('5 mm'), 2).toString(), '10 mm');
assert.equal(dotMultiply(unit('5 mm'), 0).toString(), '0 mm');
});
it('should throw an error with strings', function() {
// string
assert.throws(function () {dotMultiply("hello", "world")});
assert.throws(function () {dotMultiply("hello", 2)});
});
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 () {
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 () {
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() {
assert.throws(function () {dotMultiply(1)}, /TypeError: Too few arguments/);
assert.throws(function () {dotMultiply(1, 2, 3)}, /TypeError: Too many arguments/);
});
it('should LaTeX dotMultiply', function () {
var expression = math.parse('dotMultiply([1,2],[3,4])');
assert.equal(expression.toTex(), '\\left(\\begin{bmatrix}1\\\\2\\\\\\end{bmatrix}.\\cdot\\begin{bmatrix}3\\\\4\\\\\\end{bmatrix}\\right)');
});
});

View File

@@ -0,0 +1,180 @@
// test exp
var assert = require('assert'),
approx = require('../../../tools/approx'),
math = require('../../../index'),
complex = math.complex,
matrix = math.matrix,
sparse = math.sparse,
unit = math.unit,
dotPow = math.dotPow;
describe('dotPow', function() {
it('should elevate a number to the given power', function() {
approx.deepEqual(dotPow(2,3), 8);
approx.deepEqual(dotPow(2,4), 16);
approx.deepEqual(dotPow(-2,2), 4);
approx.deepEqual(dotPow(3,3), 27);
approx.deepEqual(dotPow(3,-2), 0.111111111111111);
approx.deepEqual(dotPow(-3,-2), 0.111111111111111);
approx.deepEqual(dotPow(3,-3), 0.0370370370370370);
approx.deepEqual(dotPow(-3,-3), -0.0370370370370370);
approx.deepEqual(dotPow(2,1.5), 2.82842712474619);
approx.deepEqual(dotPow(-2,1.5), complex(0, -2.82842712474619));
});
it('should elevate booleans to the given power', function() {
assert.equal(dotPow(true, true), 1);
assert.equal(dotPow(true, false), 1);
assert.equal(dotPow(false, true), 0);
assert.equal(dotPow(false, false), 1);
});
it('should exponentiate mixed numbers and booleans', function() {
assert.equal(dotPow(2, true), 2);
assert.equal(dotPow(2, false), 1);
assert.equal(dotPow(true, 2), 1);
assert.equal(dotPow(false, 2), 0);
});
it('should exponentiate numbers and null', function () {
assert.equal(dotPow(1, null), 1);
assert.equal(dotPow(null, 1), 0);
});
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/);
});
it('should elevate a complex number to the given power', function() {
approx.deepEqual(dotPow(complex(-1,-1),complex(-1,-1)), complex('-0.0284750589322119 + 0.0606697332231795i'));
approx.deepEqual(dotPow(complex(-1,-1),complex(-1,1)), complex('-6.7536199239765713 + 3.1697803027015614i'));
approx.deepEqual(dotPow(complex(-1,-1),complex(0,-1)), complex('0.0891447921553914 - 0.0321946742909677i'));
approx.deepEqual(dotPow(complex(-1,-1),complex(0,1)), complex('9.92340022667813 + 3.58383962127501i'));
approx.deepEqual(dotPow(complex(-1,-1),complex(1,-1)), complex('-0.1213394664463591 - 0.0569501178644237i'));
approx.deepEqual(dotPow(complex(-1,-1),complex(1,1)), complex('-6.3395606054031211 - 13.5072398479531426i'));
approx.deepEqual(dotPow(complex(-1,1),complex(-1,-1)), complex('-6.7536199239765713 - 3.1697803027015614i'));
approx.deepEqual(dotPow(complex(-1,1),complex(-1,1)), complex('-0.0284750589322119 - 0.0606697332231795i'));
approx.deepEqual(dotPow(complex(-1,1),complex(0,-1)), complex('9.92340022667813 - 3.58383962127501i'));
approx.deepEqual(dotPow(complex(-1,1),complex(0,1)), complex('0.0891447921553914 + 0.0321946742909677i'));
approx.deepEqual(dotPow(complex(-1,1),complex(1,-1)), complex('-6.3395606054031211 + 13.5072398479531426i'));
approx.deepEqual(dotPow(complex(-1,1),complex(1,1)), complex('-0.1213394664463591 + 0.0569501178644237i'));
approx.deepEqual(dotPow(complex(0,-1),complex(-1,-1)), complex('0.000000000000000 + 0.207879576350762i'));
approx.deepEqual(dotPow(complex(0,-1),complex(-1,1)), complex('0.000000000000000 + 4.810477380965351i'));
approx.deepEqual(dotPow(complex(0,-1),complex(1,-1)), complex('0.000000000000000 - 0.207879576350762i'));
approx.deepEqual(dotPow(complex(0,-1),complex(1,1)), complex('0.000000000000000 - 4.810477380965351i'));
approx.deepEqual(dotPow(complex(0,1),complex(-1,-1)), complex('0.000000000000000 - 4.810477380965351i'));
approx.deepEqual(dotPow(complex(0,1),complex(-1,1)), complex('0.000000000000000 - 0.207879576350762i'));
approx.deepEqual(dotPow(complex(0,1),complex(1,-1)), complex('0.000000000000000 + 4.810477380965351i'));
approx.deepEqual(dotPow(complex(0,1),complex(1,1)), complex('0.000000000000000 + 0.207879576350762i'));
approx.deepEqual(dotPow(complex(1,-1),complex(-1,-1)), complex('0.2918503793793073 + 0.1369786269150605i'));
approx.deepEqual(dotPow(complex(1,-1),complex(-1,1)), complex('0.6589325864505904 + 1.4039396486303144i'));
approx.deepEqual(dotPow(complex(1,-1),complex(0,-1)), complex('0.428829006294368 - 0.154871752464247i'));
approx.deepEqual(dotPow(complex(1,-1),complex(0,1)), complex('2.062872235080905 + 0.745007062179724i'));
approx.deepEqual(dotPow(complex(1,-1),complex(1,-1)), complex('0.2739572538301211 - 0.5837007587586147i'));
approx.deepEqual(dotPow(complex(1,-1),complex(1,1)), complex('2.8078792972606288 - 1.3178651729011805i'));
approx.deepEqual(dotPow(complex(1,1),complex(-1,-1)), complex('0.6589325864505904 - 1.4039396486303144i'));
approx.deepEqual(dotPow(complex(1,1),complex(-1,1)), complex('0.2918503793793073 - 0.1369786269150605i'));
approx.deepEqual(dotPow(complex(1,1),complex(0,-1)), complex('2.062872235080905 - 0.745007062179724i'));
approx.deepEqual(dotPow(complex(1,1),complex(0,1)), complex('0.428829006294368 + 0.154871752464247i'));
approx.deepEqual(dotPow(complex(1,1),complex(1,-1)), complex('2.8078792972606288 + 1.3178651729011805i'));
approx.deepEqual(dotPow(complex(1,1),complex(1,1)), complex('0.2739572538301211 + 0.5837007587586147i'));
});
it('should throw an error with units', function() {
assert.throws(function () {dotPow(unit('5cm'));});
});
it('should throw an error with strings', function() {
assert.throws(function () {dotPow('text');});
});
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)');
});
});

View File

@@ -0,0 +1,89 @@
// test exp
var assert = require('assert'),
approx = require('../../../tools/approx'),
math = require('../../../index'),
complex = math.complex,
matrix = math.matrix,
sparse = math.sparse,
unit = math.unit,
exp = math.exp;
describe('exp', function() {
it('should exponentiate a boolean', function () {
approx.equal(exp(true), 2.71828182845905);
approx.equal(exp(false), 1);
});
it('should exponentiate null', function () {
assert.equal(exp(null), 1);
});
it('should exponentiate a number', function() {
approx.equal(exp(-3), 0.0497870683678639);
approx.equal(exp(-2), 0.1353352832366127);
approx.equal(exp(-1), 0.3678794411714423);
approx.equal(exp(0), 1);
approx.equal(exp(1), 2.71828182845905);
approx.equal(exp(2), 7.38905609893065);
approx.equal(exp(3), 20.0855369231877);
approx.equal(exp(math.log(100)), 100);
});
it('should exponentiate a bignumber', function() {
var bigmath = math.create({precision: 100});
assert.deepEqual(bigmath.exp(bigmath.bignumber(1)), bigmath.bignumber('2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427'));
});
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/);
});
it('should exponentiate a complex number correctly', function() {
approx.deepEqual(exp(math.i), complex('0.540302305868140 + 0.841470984807897i'));
approx.deepEqual(exp(complex(0, -1)), complex('0.540302305868140 - 0.841470984807897i'));
approx.deepEqual(exp(complex(1, 1)), complex('1.46869393991589 + 2.28735528717884i'));
approx.deepEqual(exp(complex(1, -1)), complex('1.46869393991589 - 2.28735528717884i'));
approx.deepEqual(exp(complex(-1, -1)), complex('0.198766110346413 - 0.309559875653112i'));
approx.deepEqual(exp(complex(-1, 1)), complex('0.198766110346413 + 0.309559875653112i'));
approx.deepEqual(exp(complex(1, 0)), complex('2.71828182845905'));
// test some logic identities
var multiply = math.multiply,
pi = math.pi,
i = math.i;
approx.deepEqual(exp(multiply( 0.5, multiply(pi, i))), complex(0, 1));
approx.deepEqual(exp(multiply( 1, multiply(pi, i))), complex(-1, 0));
approx.deepEqual(exp(multiply( 1.5, multiply(pi, i))), complex(0, -1));
approx.deepEqual(exp(multiply( 2, multiply(pi, i))), complex(1, 0));
approx.deepEqual(exp(multiply(-0.5, multiply(pi, i))), complex(0, -1));
approx.deepEqual(exp(multiply(-1, multiply(pi, i))), complex(-1, 0));
approx.deepEqual(exp(multiply(-1.5, multiply(pi, i))), complex(0, 1));
});
it('should throw an error on a unit', function() {
assert.throws(function () {exp(unit('5cm'));});
});
it('should throw an error with a string', function() {
assert.throws(function () {exp('text');});
});
it('should exponentiate matrices, arrays and ranges correctly', function() {
// 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)');
});
});

View File

@@ -0,0 +1,100 @@
// test fix
var assert = require('assert');
var approx = require('../../../tools/approx');
var math = require('../../../index');
var bignumber = math.bignumber;
var complex = math.complex;
var fraction = math.fraction;
var matrix = math.matrix;
var unit = math.unit;
var range = math.range;
var fix = math.fix;
describe('fix', function() {
it('should round booleans correctly', function () {
assert.equal(fix(true), 1);
assert.equal(fix(false), 0);
});
it('should round null', function () {
assert.equal(math.ceil(null), 0);
});
it('should round numbers correctly', function() {
approx.equal(fix(0), 0);
approx.equal(fix(1), 1);
approx.equal(fix(1.3), 1);
approx.equal(fix(1.8), 1);
approx.equal(fix(2), 2);
approx.equal(fix(-1), -1);
approx.equal(fix(-1.3), -1);
approx.equal(fix(-1.8), -1);
approx.equal(fix(-2), -2);
approx.equal(fix(-2.1), -2);
approx.equal(fix(math.pi), 3);
});
it('should round big numbers correctly', function() {
assert.deepEqual(fix(bignumber(0)), bignumber(0));
assert.deepEqual(fix(bignumber(1)), bignumber(1));
assert.deepEqual(fix(bignumber(1.3)), bignumber(1));
assert.deepEqual(fix(bignumber(1.8)), bignumber(1));
assert.deepEqual(fix(bignumber(2)), bignumber(2));
assert.deepEqual(fix(bignumber(-1)), bignumber(-1));
assert.deepEqual(fix(bignumber(-1.3)), bignumber(-1));
assert.deepEqual(fix(bignumber(-1.8)), bignumber(-1));
assert.deepEqual(fix(bignumber(-2)), bignumber(-2));
assert.deepEqual(fix(bignumber(-2.1)), bignumber(-2));
});
it('should round complex numbers correctly', function() {
// complex
approx.deepEqual(fix(complex(0, 0)), complex(0, 0));
approx.deepEqual(fix(complex(1.3, 1.8)), complex(1, 1));
approx.deepEqual(fix(math.i), complex(0, 1));
approx.deepEqual(fix(complex(-1.3, -1.8)), complex(-1, -1));
});
it('should round fractions correctly', function() {
var a = fraction('2/3');
assert(fix(a) instanceof math.type.Fraction);
assert.equal(a.toString(), '0.(6)');
assert.equal(fix(fraction(0)).toString(), '0');
assert.equal(fix(fraction(1)).toString(), '1');
assert.equal(fix(fraction(1.3)).toString(), '1');
assert.equal(fix(fraction(1.8)).toString(), '1');
assert.equal(fix(fraction(2)).toString(), '2');
assert.equal(fix(fraction(-1)).toString(), '-1');
assert.equal(fix(fraction(-1.3)).toString(), '-1');
assert.equal(fix(fraction(-1.8)).toString(), '-1');
assert.equal(fix(fraction(-2)).toString(), '-2');
assert.equal(fix(fraction(-2.1)).toString(), '-2');
});
it('should throw an error on unit as parameter', function() {
// unit
assert.throws(function () {fix(unit('5cm'))}, TypeError, 'Function fix(unit) not supported');
});
it('should convert a string to a number', function() {
assert.strictEqual(fix('1.8'), 1);
});
it('should correctly round all values of a matrix element-wise', function() {
// matrix, array, range
approx.deepEqual(fix([1.2, 3.4, 5.6, 7.8, 10.0]), [1, 3, 5, 7, 10]);
approx.deepEqual(fix(matrix([1.2, 3.4, 5.6, 7.8, 10.0])), matrix([1, 3, 5, 7, 10]));
});
it('should throw an error in case of invalid number of arguments', function() {
assert.throws(function () {fix()}, /TypeError: Too few arguments/);
assert.throws(function () {fix(1, 2)}, /TypeError: Too many arguments/);
});
it('should LaTeX fix', function () {
var expression = math.parse('fix(0.6)');
assert.equal(expression.toTex(), '\\mathrm{fix}\\left(0.6\\right)');
});
});

View File

@@ -0,0 +1,97 @@
// test floor
var assert = require('assert');
var approx = require('../../../tools/approx');
var math = require('../../../index');
var bignumber = math.bignumber;
var complex = math.complex;
var fraction = math.fraction;
var matrix = math.matrix;
var unit = math.unit;
var range = math.range;
var floor = math.floor;
describe('floor', function() {
it('should round booleans correctly', function () {
assert.equal(floor(true), 1);
assert.equal(floor(false), 0);
});
it('should round null', function () {
assert.equal(floor(null), 0);
});
it('should floor numbers correctly', function() {
approx.equal(floor(0), 0);
approx.equal(floor(1), 1);
approx.equal(floor(1.3), 1);
approx.equal(floor(1.8), 1);
approx.equal(floor(2), 2);
approx.equal(floor(-1), -1);
approx.equal(floor(-1.3), -2);
approx.equal(floor(-1.8), -2);
approx.equal(floor(-2), -2);
approx.equal(floor(-2.1), -3);
approx.equal(floor(math.pi), 3);
});
it('should floor big numbers correctly', function() {
assert.deepEqual(floor(bignumber(0)), bignumber(0));
assert.deepEqual(floor(bignumber(1)), bignumber(1));
assert.deepEqual(floor(bignumber(1.3)), bignumber(1));
assert.deepEqual(floor(bignumber(1.8)), bignumber(1));
assert.deepEqual(floor(bignumber(2)), bignumber(2));
assert.deepEqual(floor(bignumber(-1)), bignumber(-1));
assert.deepEqual(floor(bignumber(-1.3)), bignumber(-2));
assert.deepEqual(floor(bignumber(-1.8)), bignumber(-2));
assert.deepEqual(floor(bignumber(-2)), bignumber(-2));
assert.deepEqual(floor(bignumber(-2.1)), bignumber(-3));
});
it('should floor complex numbers correctly', function() {
approx.deepEqual(floor(complex(0, 0)), complex(0, 0));
approx.deepEqual(floor(complex(1.3, 1.8)), complex(1, 1));
approx.deepEqual(floor(math.i), complex(0, 1));
approx.deepEqual(floor(complex(-1.3, -1.8)), complex(-2, -2));
});
it('should floor fractions correctly', function() {
var a = fraction('2/3');
assert(floor(a) instanceof math.type.Fraction);
assert.equal(a.toString(), '0.(6)');
assert.equal(floor(fraction(0)).toString(), '0');
assert.equal(floor(fraction(1)).toString(), '1');
assert.equal(floor(fraction(1.3)).toString(), '1');
assert.equal(floor(fraction(1.8)).toString(), '1');
assert.equal(floor(fraction(2)).toString(), '2');
assert.equal(floor(fraction(-1)).toString(), '-1');
assert.equal(floor(fraction(-1.3)).toString(), '-2');
assert.equal(floor(fraction(-1.8)).toString(), '-2');
assert.equal(floor(fraction(-2)).toString(), '-2');
assert.equal(floor(fraction(-2.1)).toString(), '-3');
});
it('should throw an error with a unit', function() {
assert.throws(function () {floor(unit('5cm'))}, TypeError, 'Function floor(unit) not supported');
});
it('should convert a string to a number', function() {
assert.strictEqual(floor('1.8'), 1);
});
it('should floor all elements in a matrix', function() {
approx.deepEqual(floor([1.2, 3.4, 5.6, 7.8, 10.0]), [1, 3, 5, 7, 10]);
approx.deepEqual(floor(matrix([1.2, 3.4, 5.6, 7.8, 10.0])), matrix([1, 3, 5, 7, 10]));
});
it('should throw an error in case of invalid number of arguments', function() {
assert.throws(function () {floor()}, /TypeError: Too few arguments/);
assert.throws(function () {floor(1, 2)}, /TypeError: Too many arguments/);
});
it('should LaTeX floor', function () {
var expression = math.parse('floor(0.6)');
assert.equal(expression.toTex(), '\\left\\lfloor0.6\\right\\rfloor');
});
});

View File

@@ -0,0 +1,173 @@
// test gcd
var assert = require('assert'),
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);
assert.strictEqual(gcd(8, -12), 4);
assert.strictEqual(gcd(-12, 8), 4);
assert.strictEqual(gcd(12, -8), 4);
assert.strictEqual(gcd(15, 3), 3);
assert.strictEqual(gcd(25, 15, -10, 30), 5);
});
it ('should calculate gcd for edge cases around zero', function () {
assert.strictEqual(gcd(3, 0), 3);
assert.strictEqual(gcd(-3, 0), 3);
assert.strictEqual(gcd(0, 3), 3);
assert.strictEqual(gcd(0, -3), 3);
assert.strictEqual(gcd(0, 0), 0);
assert.strictEqual(gcd(1, 1), 1);
assert.strictEqual(gcd(1, 0), 1);
assert.strictEqual(gcd(1, -1), 1);
assert.strictEqual(gcd(-1, 1), 1);
assert.strictEqual(gcd(-1, 0), 1);
assert.strictEqual(gcd(-1, -1), 1);
assert.strictEqual(gcd(0, 1), 1);
assert.strictEqual(gcd(0, -1), 1);
assert.strictEqual(gcd(0, 0), 0);
});
it ('should calculate gcd for edge cases with negative values', function () {
assert.deepEqual(1, gcd(2, 5));
assert.deepEqual(1, gcd(2, -5));
assert.deepEqual(1, gcd(-2, 5));
assert.deepEqual(1, gcd(-2, -5));
assert.deepEqual(2, gcd(2, 6));
assert.deepEqual(2, gcd(2, -6));
assert.deepEqual(2, gcd(-2, 6));
assert.deepEqual(2, gcd(-2, -6));
});
it('should calculate gcd for BigNumbers', function() {
assert.deepEqual(gcd(math.bignumber(12), math.bignumber(8)), math.bignumber(4));
assert.deepEqual(gcd(math.bignumber(8), math.bignumber(12)), math.bignumber(4));
});
it('should calculate gcd for mixed BigNumbers and Numbers', function() {
assert.deepEqual(gcd(math.bignumber(12), 8), math.bignumber(4));
assert.deepEqual(gcd(8, math.bignumber(12)), math.bignumber(4));
});
it('should find the greatest common divisor of fractions', function () {
var a = math.fraction(5,8);
assert.equal(gcd(a, math.fraction(3,7)).toString(), '0.017(857142)');
assert.equal(a.toString(), '0.625');
});
it('should find the greatest common divisor of mixed numbers and fractions', function () {
assert.deepEqual(gcd(math.fraction(12), 8), math.fraction(4));
assert.deepEqual(gcd(12, math.fraction(8)), math.fraction(4));
});
it('should find the greatest common divisor of booleans', function() {
assert.equal(gcd(true, true), 1);
assert.equal(gcd(true, false), 1);
assert.equal(gcd(false, true), 1);
assert.equal(gcd(false, false), 0);
});
it('should find the greatest common divisor of numbers and null', function () {
assert.equal(gcd(1, null), 1);
assert.equal(gcd(null, 1), 1);
assert.equal(gcd(null, null), 0);
});
it('should throw an error if only one argument', function() {
assert.throws(function () {gcd(1); }, /TypeError: Too few arguments/);
});
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/);
});
it('should convert strings to numbers', function() {
assert.strictEqual(gcd('12', '8'), 4);
assert.strictEqual(gcd(12, '8'), 4);
assert.strictEqual(gcd('12', 8), 4);
assert.throws(function () {gcd('a', 8); }, /Cannot convert "a" to a number/);
});
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 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)');
});
});

View File

@@ -0,0 +1,56 @@
// test hypot
var assert = require('assert');
var approx = require('../../../tools/approx');
var math = require('../../../index');
var hypot = math.hypot;
var bignumber = math.bignumber;
var fraction = math.fraction;
describe('hypot', function() {
it('should return the hypot of numbers', function () {
assert.strictEqual(hypot(3, 4), 5);
assert.strictEqual(hypot(3, -4), 5);
approx.equal(hypot(3, 4, 5), 7.0710678118654755);
assert.strictEqual(hypot(-2), 2);
assert.strictEqual(hypot(0), 0);
assert.strictEqual(hypot(Infinity), Infinity);
});
it('should return the hypot of BigNumbers', function () {
assert.deepEqual(hypot(bignumber(3), bignumber(4)), bignumber(5));
assert.deepEqual(hypot(bignumber(3), bignumber(-4)), bignumber(5));
assert.deepEqual(hypot(bignumber(3), bignumber(4), bignumber(5)),
bignumber('7.07106781186547524400844362104849039284835937688474036588339869'));
assert.deepEqual(hypot(bignumber(-2)), bignumber(2));
});
it('should return the hypot of an Array with numbers', function () {
assert.strictEqual(hypot([3, 4]), 5);
});
it('should return the hypot of an Matrix with numbers', function () {
assert.strictEqual(hypot(math.matrix([3, 4])), 5);
});
it('should return the hypot of an Array with mixed numbers and BigNumbers', function () {
assert.deepEqual(hypot([3, bignumber(4)]), bignumber(5));
});
it('should throw an error in case of invalid number of arguments', function() {
assert.throws(function () {hypot()}, /TypeError: Too few arguments/);
assert.throws(function () {hypot([], 2)}, /TypeError: Too many arguments/);
});
it('should throw an error in case of unsupported types', function () {
assert.throws(function () {hypot(new Date());}, /TypeError: Unexpected type of argument/);
assert.throws(function () {hypot([new Date()]);}, /TypeError: Unexpected type of argument/);
assert.throws(function () {hypot([2, 3, math.complex()]);}, /TypeError: Unexpected type of argument/);
assert.throws(function () {hypot(undefined);}, /TypeError: Unexpected type of argument/);
});
it('should LaTeX hypot', function () {
var expression = math.parse('hypot(3,4)');
assert.equal(expression.toTex(),'\\hypot\\left(3,4\\right)');
});
});

View File

@@ -0,0 +1,169 @@
var assert = require('assert'),
math = require('../../../index'),
matrix = math.matrix,
sparse = math.sparse,
lcm = math.lcm;
describe('lcm', function() {
it('should find the lowest common multiple of two or more numbers', function() {
assert.equal(lcm(4, 6), 12);
assert.equal(lcm(4, -6), 12);
assert.equal(lcm(6, 4), 12);
assert.equal(lcm(-6, 4), 12);
assert.equal(lcm(-6, -4), 12);
assert.equal(lcm(21, 6), 42);
assert.equal(lcm(3, -4, 24), 24);
assert.throws(function () {lcm(1); }, /TypeError: Too few arguments/);
});
it ('should calculate lcm for edge cases around zero', function () {
assert.equal(lcm(3, 0), 0);
assert.equal(lcm(-3, 0), 0);
assert.equal(lcm(0, 3), 0);
assert.equal(lcm(0, -3), 0);
assert.equal(lcm(0, 0), 0);
assert.equal(lcm(1, 1), 1);
assert.equal(lcm(1, 0), 0);
assert.equal(lcm(1, -1), 1);
assert.equal(lcm(-1, 1), 1);
assert.equal(lcm(-1, 0), 0);
assert.equal(lcm(-1, -1), 1);
assert.equal(lcm(0, 1), 0);
assert.equal(lcm(0, -1), 0);
assert.equal(lcm(0, 0), 0);
});
it('should calculate lcm for BigNumbers', function() {
assert.deepEqual(lcm(math.bignumber(4), math.bignumber(6)), math.bignumber(12));
assert.deepEqual(lcm(math.bignumber(4), math.bignumber(6)), math.bignumber(12));
});
it('should calculate lcm for mixed BigNumbers and Numbers', function() {
assert.deepEqual(lcm(math.bignumber(4), 6), math.bignumber(12));
assert.deepEqual(lcm(4, math.bignumber(6)), math.bignumber(12));
});
it('should find the lowest common multiple of booleans', function() {
assert.equal(lcm(true, true), 1);
assert.equal(lcm(true, false), 0);
assert.equal(lcm(false, true), 0);
assert.equal(lcm(false, false), 0);
});
it('should find the lowest common multiple of numbers and null', function () {
assert.equal(lcm(1, null), 0);
assert.equal(lcm(null, 1), 0);
assert.equal(lcm(null, null), 0);
});
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');
});
it('should convert strings to numbers', function() {
assert.equal(lcm('4', '6'), 12);
assert.equal(lcm('4', 6), 12);
assert.equal(lcm(4, '6'), 12);
assert.throws(function () {lcm('a', 2); }, /Cannot convert "a" to a number/);
});
it('should find the least common multiple of fractions', function () {
var a = math.fraction(5,8);
assert.equal(lcm(a, math.fraction(3,7)).toString(), '15');
assert.equal(a.toString(), '0.625');
});
it('should find the least common multiple of mixed numbers and fractions', function () {
assert.deepEqual(lcm(math.fraction(12), 8), math.fraction(24));
assert.deepEqual(lcm(12, math.fraction(8)), math.fraction(24));
});
it('should find the least common even for edge cases', function () {
assert.deepEqual(lcm(math.fraction(-3), math.fraction(3)), math.fraction(3));
assert.deepEqual(lcm(math.fraction(3), math.fraction(-3)), math.fraction(3));
assert.deepEqual(lcm(math.fraction(0), math.fraction(3)), math.fraction(0));
assert.deepEqual(lcm(math.fraction(3), math.fraction(0)), math.fraction(0));
assert.deepEqual(lcm(math.fraction(0), math.fraction(0)), math.fraction(0));
assert.deepEqual(lcm(math.fraction(200), math.fraction(333)), math.fraction(66600));
assert.deepEqual(lcm(math.fraction(9999), math.fraction(8888)), math.fraction(79992));
});
it('should throw an error with units', function() {
assert.throws(function () { lcm(math.unit('5cm'), 2); }, TypeError, 'Function lcm(unit, number) not supported');
});
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)');
});
});

View File

@@ -0,0 +1,122 @@
// test log
var assert = require('assert');
var approx = require('../../../tools/approx');
var error = require('../../../lib/error/index');
var math = require('../../../index');
var mathPredictable = math.create({predictable: true});
var complex = math.complex;
var matrix = math.matrix;
var unit = math.unit;
var range = math.range;
var log = math.log;
describe('log', function() {
it('should return the log of a boolean value', function () {
assert.equal(log(true), 0);
assert.equal(log(false), -Infinity);
assert.equal(log(1,false), 0);
});
it('should return the log of null', function () {
assert.equal(log(null), -Infinity);
assert.equal(log(1, null), 0);
});
it('should return the log of positive numbers', function() {
approx.deepEqual(log(1), 0);
approx.deepEqual(log(2), 0.693147180559945);
approx.deepEqual(log(3), 1.098612288668110);
approx.deepEqual(math.exp(log(100)), 100);
});
it('should return the log of negative numbers', function() {
approx.deepEqual(log(-1), complex('0.000000000000000 + 3.141592653589793i'));
approx.deepEqual(log(-2), complex('0.693147180559945 + 3.141592653589793i'));
approx.deepEqual(log(-3), complex('1.098612288668110 + 3.141592653589793i'));
});
it('should return the log of negative numbers with predictable: true', function() {
assert.equal(typeof mathPredictable.log(-1), 'number');
assert(isNaN(mathPredictable.log(-1)));
});
it('should return the log of zero', function() {
approx.deepEqual(log(0), -Infinity);
});
it('should return the log base N of a number', function() {
approx.deepEqual(log(100, 10), 2);
approx.deepEqual(log(1000, 10), 3);
approx.deepEqual(log(8, 2), 3);
approx.deepEqual(log(16, 2), 4);
});
it('should throw an error if invalid number of arguments', function() {
assert.throws(function () {log()}, /TypeError: Too few arguments in function log \(expected: any, index: 1\)/);
assert.throws(function () {log(1, 2, 3)}, /TypeError: Too many arguments in function log \(expected: 2, actual: 3\)/);
});
it('should return the log of positive bignumbers', function() {
var bigmath = math.create({precision: 100});
assert.deepEqual(bigmath.log(bigmath.bignumber(1)), bigmath.bignumber('0'));
assert.deepEqual(bigmath.log(bigmath.bignumber(2)), bigmath.bignumber('0.6931471805599453094172321214581765680755001343602552541206800094933936219696947156058633269964186875'));
assert.deepEqual(bigmath.log(bigmath.bignumber(3)), bigmath.bignumber('1.098612288668109691395245236922525704647490557822749451734694333637494293218608966873615754813732089'));
// note: the following gives a round-off error with regular numbers
assert.deepEqual(bigmath.log(bigmath.bignumber(1000), bigmath.bignumber(10)), bigmath.bignumber(3));
});
it('should return the log of negative bignumbers', function() {
var bigmath = math.create({precision: 100});
approx.deepEqual(bigmath.log(bigmath.bignumber(-1)), complex('0.000000000000000 + 3.141592653589793i'));
approx.deepEqual(bigmath.log(bigmath.bignumber(-2)), complex('0.693147180559945 + 3.141592653589793i'));
approx.deepEqual(bigmath.log(bigmath.bignumber(-3)), complex('1.098612288668110 + 3.141592653589793i'));
});
it('should return the log of negative bignumbers with predictable:true', function() {
assert.ok(mathPredictable.log(math.bignumber(-1)).isNaN());
});
it('should return the log of a bignumber with value zero', function() {
var bigmath = math.create({precision: 100});
assert.deepEqual(bigmath.log(bigmath.bignumber(0)).toString(), '-Infinity');
});
it('should return the log of a complex number', function() {
approx.deepEqual(log(math.i), complex('1.570796326794897i'));
approx.deepEqual(log(complex(0, -1)), complex('-1.570796326794897i'));
approx.deepEqual(log(complex(1, 1)), complex('0.346573590279973 + 0.785398163397448i'));
approx.deepEqual(log(complex(1, -1)), complex('0.346573590279973 - 0.785398163397448i'));
approx.deepEqual(log(complex(-1, -1)), complex('0.346573590279973 - 2.356194490192345i'));
approx.deepEqual(log(complex(-1, 1)), complex('0.346573590279973 + 2.356194490192345i'));
approx.deepEqual(log(complex(1, 0)), complex(0, 0));
});
it('should throw an error when used on a unit', function() {
assert.throws(function () {log(unit('5cm'))});
});
it('should throw an error when used on a string', function() {
assert.throws(function () {log('text')});
});
it('should return the log of each element of a matrix', function() {
var res = [0, 0.693147180559945, 1.098612288668110, 1.386294361119891];
approx.deepEqual(log([1,2,3,4]), res);
approx.deepEqual(log(matrix([1,2,3,4])), matrix(res));
approx.deepEqual(log(matrix([[1,2],[3,4]])),
matrix([[0, 0.693147180559945], [1.098612288668110, 1.386294361119891]]));
});
it('should LaTeX log', function () {
var expr1 = math.parse('log(e)');
var expr2 = math.parse('log(32,2)');
assert.equal(expr1.toTex(), '\\ln\\left( e\\right)');
assert.equal(expr2.toTex(), '\\log_{2}\\left(32\\right)');
});
});

View File

@@ -0,0 +1,113 @@
// test exp
var assert = require('assert');
var approx = require('../../../tools/approx');
var math = require('../../../index');
var mathPredictable = math.create({predictable: true});
var complex = math.complex;
var matrix = math.matrix;
var unit = math.unit;
var range = math.range;
var log10 = math.log10;
describe('log10', function() {
it('should return the log base 10 of a boolean', function () {
assert.equal(log10(true), 0);
assert.equal(log10(false), -Infinity);
});
it('should return the log base 10 of null', function () {
assert.equal(log10(null), -Infinity);
});
it('should return the log base 10 of positive numbers', function() {
approx.deepEqual(log10(1), 0);
approx.deepEqual(log10(2), 0.301029995663981);
approx.deepEqual(log10(3), 0.477121254719662);
approx.deepEqual(log10(0.01), -2);
approx.deepEqual(log10(0.1), -1);
approx.deepEqual(log10(1), 0);
approx.deepEqual(log10(10), 1);
approx.deepEqual(log10(100), 2);
approx.deepEqual(log10(1000), 3);
});
it('should return the log base 10 of negative numbers', function() {
approx.deepEqual(log10(-1), complex('0.000000000000000 + 1.364376353841841i'));
approx.deepEqual(log10(-2), complex('0.301029995663981 + 1.364376353841841i'));
approx.deepEqual(log10(-3), complex('0.477121254719662 + 1.364376353841841i'));
});
it('should return the log base 10 of negative numbers with predicable:true', function() {
assert.equal(typeof mathPredictable.log10(-1), 'number');
assert(isNaN(mathPredictable.log10(-1)));
});
it('should return the log base 10 of zero', function() {
approx.deepEqual(log10(0), -Infinity);
});
it('should return the log of positive bignumbers', function() {
var bigmath = math.create({precision: 100});
assert.deepEqual(bigmath.log10(bigmath.bignumber(1)), bigmath.bignumber(0));
assert.deepEqual(bigmath.log10(bigmath.bignumber(10)), bigmath.bignumber(1));
assert.deepEqual(bigmath.log10(bigmath.bignumber(100)), bigmath.bignumber(2));
assert.deepEqual(bigmath.log10(bigmath.bignumber(1000)), bigmath.bignumber(3)); // note: this gives a round-off error with regular numbers
assert.deepEqual(bigmath.log10(bigmath.bignumber(10000)), bigmath.bignumber(4));
assert.deepEqual(bigmath.log10(bigmath.bignumber('1e500')), bigmath.bignumber(500));
});
it('should return the log of negative bignumbers', function() {
var bigmath = math.create({precision: 100});
approx.deepEqual(bigmath.log10(bigmath.bignumber(-1)), bigmath.complex('0.000000000000000 + 1.364376353841841i'));
approx.deepEqual(bigmath.log10(bigmath.bignumber(-2)), bigmath.complex('0.301029995663981 + 1.364376353841841i'));
approx.deepEqual(bigmath.log10(bigmath.bignumber(-3)), bigmath.complex('0.477121254719662 + 1.364376353841841i'));
});
it('should return the log of a bignumber with value zero', function() {
var bigmath = math.create({precision: 100});
assert.deepEqual(bigmath.log10(bigmath.bignumber(0)).toString(), '-Infinity');
});
it('should throw an error if used with a wrong number of arguments', function() {
assert.throws(function () {log10()}, /TypeError: Too few arguments/);
assert.throws(function () {log10(1, 2)}, /TypeError: Too many arguments/);
});
it('should return the log base 10 of a complex number', function() {
approx.deepEqual(log10(complex(0, 1)), complex('0.000000000000000 + 0.682188176920921i'));
approx.deepEqual(log10(complex(0, -1)), complex('0.000000000000000 - 0.682188176920921i'));
approx.deepEqual(log10(complex(1, 1)), complex('0.150514997831991 + 0.341094088460460i'));
approx.deepEqual(log10(complex(1, -1)), complex('0.150514997831991 - 0.341094088460460i'));
approx.deepEqual(log10(complex(-1, -1)), complex('0.150514997831991 - 1.023282265381381i'));
approx.deepEqual(log10(complex(-1, 1)), complex('0.150514997831991 + 1.023282265381381i'));
approx.deepEqual(log10(complex(1, 0)), complex(0, 0));
});
it('should throw an error when used on a unit', function() {
assert.throws(function () {log10(unit('5cm'))});
});
it('should throw an error when used on a string', function() {
assert.throws(function () {log10('text')});
});
it('should return the log base 10 of each element of a matrix', function() {
var res = [0, 0.301029995663981, 0.477121254719662, 0.602059991327962];
approx.deepEqual(log10([1,2,3,4]), res);
approx.deepEqual(log10(matrix([1,2,3,4])), matrix(res));
approx.deepEqual(math.divide(log10(matrix([1,2,3,4])), math.LOG10E),
matrix([0, 0.693147180559945, 1.098612288668110, 1.386294361119891]));
approx.deepEqual(log10(matrix([[1,2],[3,4]])),
matrix([[0, 0.301029995663981], [0.477121254719662, 0.602059991327962]]));
});
it('should LaTeX log10', function () {
var expression = math.parse('log10(10)');
assert.equal(expression.toTex(), '\\log_{10}\\left(10\\right)');
});
});

View File

@@ -0,0 +1,182 @@
// test mod
var assert = require('assert');
var approx = require('../../../tools/approx');
var math = require('../../../index');
var bignumber = math.bignumber;
var matrix = math.matrix;
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);
assert.equal(mod(true, false), 1);
assert.equal(mod(false, false), 0);
});
it('should calculate the modulus of numbers and null', function () {
assert.equal(mod(null, null), 0);
assert.equal(mod(null, 1), 0);
assert.equal(mod(1, null), 1);
});
it('should calculate the modulus of two numbers', function() {
assert.equal(mod(1, 1), 0);
assert.equal(mod(0, 1), 0);
assert.equal(mod(1, 0), 1);
assert.equal(mod(0, 0), 0);
assert.equal(mod(7, 0), 7);
approx.equal(mod(7, 2), 1);
approx.equal(mod(9, 3), 0);
approx.equal(mod(10, 4), 2);
approx.equal(mod(-10, 4), 2);
approx.equal(mod(8.2, 3), 2.2);
approx.equal(mod(4, 1.5), 1);
approx.equal(mod(0, 3), 0);
});
it('should throw an error if the modulus is negative', function() {
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/);
});
it('should throw an error if used with wrong type of arguments', function() {
assert.throws(function () {mod(1, new Date());}, /TypeError: Unexpected type of argument/);
assert.throws(function () {mod(new Date(), bignumber(2));}, /TypeError: Unexpected type of argument/);
});
it('should calculate the modulus of bignumbers', function() {
assert.deepEqual(mod(bignumber(7), bignumber(2)), bignumber(1));
assert.deepEqual(mod(bignumber(7), bignumber(0)), bignumber(7));
assert.deepEqual(mod(bignumber(0), bignumber(3)), bignumber(0));
assert.deepEqual(mod(bignumber(7), bignumber(2)), bignumber(1));
assert.deepEqual(mod(bignumber(8), bignumber(3)).valueOf(), bignumber(2).valueOf());
});
it.skip('should calculate the modulus of bignumbers for fractions', function () {
assert.deepEqual(mod(bignumber(7).div(3), bignumber(1).div(3)), bignumber(0));
});
it.skip('should calculate the modulus of bignumbers for negative values', function () {
assert.deepEqual(mod(bignumber(-10), bignumber(4)), bignumber(2));
});
it('should calculate the modulus of mixed numbers and bignumbers', function() {
assert.deepEqual(mod(bignumber(7), 2), bignumber(1));
assert.deepEqual(mod(bignumber(7), 0), bignumber(7));
assert.deepEqual(mod(8, bignumber(3)), bignumber(2));
assert.deepEqual(mod(7, bignumber(0)), bignumber(7));
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/);
});
it('should calculate the modulus of mixed booleans and bignumbers', function() {
assert.deepEqual(mod(bignumber(7), true), bignumber(0));
assert.deepEqual(mod(bignumber(7), false), bignumber(7));
assert.deepEqual(mod(true, bignumber(3)), bignumber(1));
assert.deepEqual(mod(false, bignumber(3)), bignumber(0));
});
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);
});
it('should convert string to number', function() {
assert.strictEqual(mod('8', '3'), 2);
assert.strictEqual(mod('8', 3), 2);
assert.strictEqual(mod(8, '3'), 2);
assert.throws(function () {mod(5, 'a');}, /Cannot convert "a" to a number/);
});
it('should calculate modulus of two fractions', function() {
var b = math.fraction(8);
var a = mod(b, math.fraction(3));
assert.equal(a.toString(), '2');
assert.equal(b.toString(), '8');
assert(a instanceof math.type.Fraction);
assert.equal(mod(math.fraction(4.55), math.fraction(0.05)).toString(), '0');
});
it('should calculate modulus of mixed fractions and numbers', function() {
assert.deepEqual(mod(8, math.fraction(3)), math.fraction(2));
assert.deepEqual(mod(math.fraction(8), 3), math.fraction(2));
});
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)');
});
});

View File

@@ -0,0 +1,892 @@
// test multiply
var assert = require('assert'),
math = require('../../../index'),
approx = require('../../../tools/approx'),
market = require('../../../tools/matrixmarket'),
multiply = math.multiply,
divide = math.divide,
matrix = math.matrix,
complex = math.complex,
bignumber = math.bignumber,
i = math.i,
unit = math.unit;
describe('multiply', function() {
describe('Scalar', function () {
it('should multiply two numbers correctly', function() {
approx.equal(multiply(2, 3), 6);
approx.equal(multiply(-2, 3), -6);
approx.equal(multiply(-2, -3), 6);
approx.equal(multiply(5, 0), 0);
approx.equal(multiply(0, 5), 0);
approx.deepEqual(multiply(0, Infinity), NaN);
approx.deepEqual(multiply(2, Infinity), Infinity);
approx.deepEqual(multiply(-2, Infinity), -Infinity);
});
it('should multiply booleans', function() {
assert.equal(multiply(true, true), 1);
assert.equal(multiply(true, false), 0);
assert.equal(multiply(false, true), 0);
assert.equal(multiply(false, false), 0);
});
it('should multiply mixed numbers and booleans', function() {
assert.equal(multiply(2, true), 2);
assert.equal(multiply(2, false), 0);
assert.equal(multiply(true, 2), 2);
assert.equal(multiply(false, 2), 0);
});
it('should multiply numbers and null', function () {
assert.equal(multiply(1, null), 0);
assert.equal(multiply(null, 1), 0);
});
it('should multiply bignumbers', function() {
assert.deepEqual(multiply(bignumber(1.5), bignumber(0.2)), bignumber(0.3));
assert.deepEqual(multiply(bignumber('1.3e5000'), bignumber('2')), bignumber('2.6e5000'));
});
it('should multiply mixed numbers and bignumbers', function() {
assert.deepEqual(multiply(bignumber(1.5), 0.2), bignumber(0.3));
assert.deepEqual(multiply(1.5, bignumber(0.2)), bignumber(0.3));
assert.deepEqual(multiply(bignumber('1.3e5000'), 2), bignumber('2.6e5000'));
assert.throws(function () {multiply(1/3, bignumber(1).div(3));}, /Cannot implicitly convert a number with >15 significant digits to BigNumber/);
assert.throws(function () {multiply(bignumber(1).div(3), 1/3);}, /Cannot implicitly convert a number with >15 significant digits to BigNumber/);
});
it('should throw an error when multipling mixed fractions and bignumbers', function() {
assert.throws(function () {multiply(math.bignumber('2'), math.fraction(1,3))}, /Cannot implicitly convert a Fraction to BigNumber/);
assert.throws(function () {multiply(math.fraction(1,3), math.bignumber('2'))}, /Cannot implicitly convert a Fraction to BigNumber/);
});
it('should multiply mixed booleans and bignumbers', function() {
assert.deepEqual(multiply(bignumber(0.3), true), bignumber(0.3));
assert.deepEqual(multiply(bignumber(0.3), false), bignumber(0));
assert.deepEqual(multiply(false, bignumber('2')), bignumber(0));
assert.deepEqual(multiply(true, bignumber('2')), bignumber(2));
});
it('should multiply two complex numbers correctly', function() {
approx.deepEqual(multiply(complex(2, 3), 2), complex(4, 6));
approx.deepEqual(multiply(complex(2, -3), -2), complex(-4, 6));
approx.deepEqual(multiply(complex(2, -3), 2), complex(4, -6));
approx.deepEqual(multiply(complex(-2, 3), 2), complex(-4, 6));
approx.deepEqual(multiply(complex(-2, -3), 2), complex(-4, -6));
approx.deepEqual(multiply(2, complex(2, 3)), complex(4, 6));
approx.deepEqual(multiply(i, complex(2, 3)), complex(-3, 2));
approx.deepEqual(multiply(complex(0, 1), complex(2, 3)), complex(-3, 2));
approx.deepEqual(multiply(complex(1, 1), complex(2, 3)), complex(-1, 5));
approx.deepEqual(multiply(complex(2, 3), complex(1, 1)), complex(-1, 5));
approx.deepEqual(multiply(complex(2, 3), complex(2, 3)), complex(-5, 12));
approx.deepEqual(divide(complex(-5, 12), complex(2, 3)), complex(2, 3));
approx.deepEqual(multiply(complex(2, 3), 0), complex(0, 0));
approx.deepEqual(multiply(complex(0, 3), complex(0, -4)), complex(12, 0));
approx.deepEqual(multiply(multiply(3, i), multiply(-4, i)), complex(12, 0));
approx.deepEqual(multiply(math.i, Infinity), complex(NaN, Infinity));
approx.deepEqual(multiply(Infinity, math.i), complex(NaN, Infinity));
approx.deepEqual(multiply(complex(2,0), complex(0,2)), complex(0, 4));
approx.deepEqual(multiply(complex(0,2), complex(0,2)), -4);
approx.deepEqual(multiply(complex(2,2), complex(0,2)), complex(-4, 4));
approx.deepEqual(multiply(complex(2,0), complex(2,2)), complex(4, 4));
approx.deepEqual(multiply(complex(0,2), complex(2,2)), complex(-4, 4));
approx.deepEqual(multiply(complex(2,2), complex(2,2)), complex(0, 8));
approx.deepEqual(multiply(complex(2,0), complex(2,0)), 4);
approx.deepEqual(multiply(complex(0,2), complex(2,0)), complex(0, 4));
approx.deepEqual(multiply(complex(2,2), complex(2,0)), complex(4, 4));
approx.deepEqual(multiply(complex(2, 3), complex(4, 5)), complex(-7, 22));
approx.deepEqual(multiply(complex(2, 3), complex(4, -5)), complex(23, 2));
approx.deepEqual(multiply(complex(2, 3), complex(-4, 5)), complex(-23, -2));
approx.deepEqual(multiply(complex(2, 3), complex(-4, -5)), complex(7, -22));
approx.deepEqual(multiply(complex(2, -3), complex(4, 5)), complex(23, -2));
approx.deepEqual(multiply(complex(2, -3), complex(4, -5)), complex(-7, -22));
approx.deepEqual(multiply(complex(2, -3), complex(-4, 5)), complex(7, 22));
approx.deepEqual(multiply(complex(2, -3), complex(-4, -5)), complex(-23, 2));
approx.deepEqual(multiply(complex(-2, 3), complex(4, 5)), complex(-23, 2));
approx.deepEqual(multiply(complex(-2, 3), complex(4, -5)), complex(7, 22));
approx.deepEqual(multiply(complex(-2, 3), complex(-4, 5)), complex(-7, -22));
approx.deepEqual(multiply(complex(-2, 3), complex(-4, -5)), complex(23, -2));
approx.deepEqual(multiply(complex(-2, -3), complex(4, 5)), complex(7, -22));
approx.deepEqual(multiply(complex(-2, -3), complex(4, -5)), complex(-23, -2));
approx.deepEqual(multiply(complex(-2, -3), complex(-4, 5)), complex(23, 2));
approx.deepEqual(multiply(complex(-2, -3), complex(-4, -5)), complex(-7, 22));
});
it('should multiply mixed complex numbers and numbers', function() {
assert.deepEqual(multiply(math.complex(6, -4), 2), math.complex(12, -8));
assert.deepEqual(multiply(2, math.complex(2, 4)), math.complex(4, 8));
});
it('should multiply mixed complex numbers and big numbers', function() {
assert.deepEqual(multiply(math.complex(6, -4), math.bignumber(2)), math.complex(12, -8));
assert.deepEqual(multiply(math.bignumber(2), math.complex(2, 4)), math.complex(4, 8));
});
it('should multiply two fractions', function() {
var a = math.fraction(1,4);
assert.equal(multiply(a, math.fraction(1,2)).toString(), '0.125');
assert.equal(a.toString(), '0.25');
assert.equal(multiply(math.fraction(2), math.fraction(1,3)).toString(), '0.(6)');
});
it('should multiply mixed fractions and numbers', function() {
assert.deepEqual(multiply(2, math.fraction(1,3)), math.fraction(2,3));
assert.deepEqual(multiply(math.fraction(1,3), 2), math.fraction(2,3));
});
it('should multiply a number and a unit correctly', function() {
assert.equal(multiply(2, unit('5 mm')).toString(), '10 mm');
assert.equal(multiply(2, unit('5 mm')).toString(), '10 mm');
assert.equal(multiply(10, unit('celsius')).toString(), '10 celsius');
assert.equal(multiply(unit('5 mm'), 2).toString(), '10 mm');
assert.equal(multiply(unit('5 mm'), 0).toString(), '0 mm');
assert.equal(multiply(unit('celsius'), 10).toString(), '10 celsius');
assert.equal(multiply(unit(math.fraction(1,4), 'm'), 3).toString(), '3/4 m');
assert.equal(multiply(3, unit(math.fraction(1,4), 'm')).toString(), '3/4 m');
assert.equal(multiply(math.fraction(1,4), unit(3, 'm')).toString(), '3/4 m');
assert.equal(multiply(unit(3, 'm'), math.fraction(1,4)).toString(), '3/4 m');
assert.equal(multiply(unit(math.complex(9, 8), 'm'), 2).toString(), '(18 + 16i) m');
assert.equal(math.format(multiply(unit(math.complex(2, 3), 'g'), math.complex(4, 5)), 14), '(-7 + 22i) g');
});
it('should multiply a number and a unit without value correctly', function() {
assert.equal(multiply(2, unit('mm')).toString(), '2 mm');
assert.equal(multiply(2, unit('km')).toString(), '2 km');
assert.equal(multiply(2, unit('inch')).toString(), '2 inch');
assert.equal(multiply(unit('mm'), 2).toString(), '2 mm');
assert.equal(multiply(unit('km'), 2).toString(), '2 km');
assert.equal(multiply(unit('inch'), 2).toString(), '2 inch');
});
it('should multiply two units correctly', function() {
assert.equal(multiply(unit('2 m'), unit('4 m')).toString(), '8 m^2');
assert.equal(multiply(unit('2 ft'), unit('4 ft')).toString(), '8 ft^2');
assert.equal(multiply(unit('65 mi/h'), unit('2 h')).to('mi').toString(), '130 mi');
assert.equal(multiply(unit('2 L'), unit('1 s^-1')).toString(), '2 L / s');
assert.equal(multiply(unit('2 m/s'), unit('0.5 s/m')).toString(), '1');
assert.equal(multiply(unit(math.complex(3,-4), 'N'), unit(math.complex(7,-2), 'm')).toString(), '(13 - 34i) J');
});
it('should multiply valueless units correctly', function() {
assert.equal(multiply(unit('m'), unit('4 m')).toString(), '4 m^2');
assert.equal(multiply(unit('ft'), unit('4 ft')).format(5), '4 ft^2');
assert.equal(multiply(unit('65 mi/h'), unit('h')).to('mi').toString(), '65 mi');
assert.equal(multiply(unit('2 L'), unit('s^-1')).toString(), '2 L / s');
assert.equal(multiply(unit('m/s'), unit('h/m')).toString(), '(m h) / (s m)');
});
// TODO: cleanup once decided to not downgrade BigNumber to number
it.skip('should multiply a bignumber and a unit correctly', function() {
assert.equal(multiply(bignumber(2), unit('5 mm')).toString(), '10 mm');
assert.equal(multiply(bignumber(2), unit('5 mm')).toString(), '10 mm');
assert.equal(multiply(unit('5 mm'), bignumber(2)).toString(), '10 mm');
assert.equal(multiply(unit('5 mm'), bignumber(0)).toString(), '0 m');
});
// TODO: cleanup once decided to not downgrade BigNumber to number
it.skip('should multiply a bignumber and a unit without value correctly', function() {
assert.equal(multiply(bignumber(2), unit('mm')).toString(), '2 mm');
assert.equal(multiply(bignumber(2), unit('km')).toString(), '2 km');
assert.equal(multiply(bignumber(2), unit('inch')).toString(), '2 inch');
assert.equal(multiply(unit('mm'), bignumber(2)).toString(), '2 mm');
assert.equal(multiply(unit('km'), bignumber(2)).toString(), '2 km');
assert.equal(multiply(unit('inch'), bignumber(2)).toString(), '2 inch');
});
it('should throw an error in case of unit non-numeric argument', function() {
// Multiplying two units is supported now
//assert.throws(function () {multiply(math.unit('5cm'), math.unit('4cm'));}, /TypeError: Unexpected type/);
// Complex units are supported now
//assert.throws(function () {multiply(math.unit('5cm'), math.complex('2+3i'));}, /TypeError: Unexpected type/);
//assert.throws(function () {multiply(math.complex('2+3i'), math.unit('5cm'));}, /TypeError: Unexpected type/);
});
it('should throw an error if used with strings', function() {
assert.throws(function () {multiply("hello", "world");});
assert.throws(function () {multiply("hello", 2);});
});
});
it('should multiply mixed array and matrix', function () {
var a = [[1, 2], [3, 4]];
var b = [[2, 0], [0, 2]];
approx.deepEqual(multiply(a, matrix(b)), matrix([[2, 4], [6, 8]]));
approx.deepEqual(multiply(matrix(a), b), matrix([[2, 4], [6, 8]]));
// test with vectors, returning a scalar
var c = [1, 2, 3];
var d = [4, 5, 6];
assert.strictEqual(multiply(c, matrix(d)), 32);
assert.strictEqual(multiply(matrix(c), d), 32);
});
describe('squeeze', function () {
// math.js v1 and v2 did squeeze output being a vector. Changed in v3
it ('should NOT squeeze scalar results of matrix * matrix', function () {
var a = [[1, 2, 3]];
var b = [[4], [5], [6]];
assert.deepEqual(multiply(a, b), [[32]]);
});
it ('should NOT squeeze scalar results of vector * matrix', function () {
var a = [1, 2, 3];
var b = [[4], [5], [6]];
assert.deepEqual(multiply(a, b), [32]);
});
it ('should NOT squeeze scalar results of matrix * vector', function () {
var a = [[1, 2, 3]];
var b = [4, 5, 6];
assert.deepEqual(multiply(a, b), [32]);
});
});
it('should throw an error when multiplying matrices with incompatible sizes', function() {
// vector * vector
assert.throws(function () {multiply([1,1], [1,1, 1]);});
// matrix * matrix
assert.throws(function () {multiply([[1,1]], [[1,1]]);});
assert.throws(function () {multiply([[1,1]], [[1,1], [1,1], [1,1]]);});
// matrix * vector
assert.throws(function () {multiply([[1,1], [1,1]], [1,1,1]);});
// vector * matrix
assert.throws(function () {multiply([1,1,1], [[1,1], [1,1]]);});
});
it('should throw an error when multiplying multi dimensional matrices', function() {
assert.throws(function () {multiply([[[1]]], [1]);});
assert.throws(function () {multiply([[[1]]], [[1]]);});
assert.throws(function () {multiply([1], [[[1]]]);});
assert.throws(function () {multiply([[1]], [[[1]]]);});
});
it('should throw an error in case of invalid number of arguments', function() {
assert.throws(function () {multiply(1);}, /TypeError: Too few arguments/);
});
describe('Vector', function () {
it('should multiply vectors correctly (dot product)', function () {
var a = [1, 2, 3];
var b = [4, 5, 6];
approx.deepEqual(multiply(a, b), 32);
approx.deepEqual(multiply(matrix(a), matrix(b)), 32);
});
it('should multiply row vector x column vector', function () {
var v = [[1, 2, 3, 0, 0, 5, 6]];
var r = multiply(v, [[3], [4], [6], [0], [1], [2], [0]]);
assert.deepEqual(r, [[39]]);
r = multiply(v, math.matrix([[3], [4], [6], [0], [1], [2], [0]], 'dense'));
assert.deepEqual(r, math.matrix([[39]], 'dense'));
r = multiply(v, math.matrix([[3], [4], [6], [0], [1], [2], [0]], 'sparse'));
assert.deepEqual(r, math.matrix([[39]], 'sparse'));
});
it('should multiply dense row vector x column vector', function () {
var v = math.matrix([[1, 2, 3, 0, 0, 5, 6]], 'dense');
var r = multiply(v, [[3], [4], [6], [0], [1], [2], [0]]);
assert.deepEqual(r, math.matrix([[39]]));
r = multiply(v, math.matrix([[3], [4], [6], [0], [1], [2], [0]], 'dense'));
assert.deepEqual(r, math.matrix([[39]]));
r = multiply(v, math.matrix([[3], [4], [6], [0], [1], [2], [0]], 'sparse'));
assert.deepEqual(r, math.matrix([[39]], 'sparse'));
});
it('should throw an error when multiplying empty vectors', function () {
assert.throws(function () {multiply([], []);}, /Cannot multiply two empty vectors/);
});
it('should multiply a vector with a matrix correctly', function () {
var a = [1, 2, 3];
var b = [
[8, 1, 6],
[3, 5, 7],
[4, 9, 2]
];
approx.deepEqual(multiply(a, b), [26, 38, 26]);
approx.deepEqual(multiply(b, a), [28, 34, 28]);
approx.deepEqual(multiply(matrix(a), matrix(b)), matrix([26, 38, 26]));
approx.deepEqual(multiply(matrix(b), matrix(a)), matrix([28, 34, 28]));
});
});
describe('Dense Matrix', function () {
it('should multiply matrix x scalar', function() {
var m = math.matrix([
[2, 0],
[4, 0]
]);
var r = multiply(m, 3);
assert.deepEqual(r._size, m._size);
assert.deepEqual(r._data, [[6, 0], [12, 0]]);
r = multiply(m, math.complex(3, 3));
assert.deepEqual(r._size, m._size);
assert.deepEqual(r._data, [[math.complex(6, 6), math.complex(0, 0)], [math.complex(12, 12), math.complex(0, 0)]]);
r = multiply(m, math.bignumber(3));
assert.deepEqual(r._size, m._size);
assert.deepEqual(r._data, [[math.bignumber(6), math.bignumber(0)], [math.bignumber(12), math.bignumber(0)]]);
r = multiply(m, true);
assert.deepEqual(r._size, m._size);
assert.deepEqual(r._data, [[2, 0], [4, 0]]);
r = multiply(m, false);
assert.deepEqual(r._size, m._size);
assert.deepEqual(r._data, [[0, 0], [0, 0]]);
});
it('should multiply matrix x matrix with zeros', function() {
var m = math.matrix([
[2, 0],
[4, 0]
]);
var r = multiply(m, math.matrix([
[2, 0],
[4, 0]
]));
assert.deepEqual(
r.valueOf(),
[
[4, 0],
[8, 0]
]);
r = multiply(m, math.matrix([
[2, 0],
[4, 0]
], 'sparse'));
assert.deepEqual(
r.valueOf(),
[
[4, 0],
[8, 0]
]);
});
it('should multiply matrix x matrix', function() {
var m = math.matrix([[1, 2], [3, 4]], 'dense');
var r = multiply(m, math.matrix([[5, 6], [7, 8]], 'sparse'));
assert.deepEqual(
r.valueOf(),
[
[19, 22],
[43, 50]
]);
r = multiply(m, math.matrix([[5, 6], [7, 8]], 'dense'));
assert.deepEqual(
r.valueOf(),
[
[19, 22],
[43, 50]
]);
});
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],
[4, 0]
]);
var r = multiply(
m,
[
[2, 0],
[4, 0]
]);
assert.deepEqual(
r.valueOf(),
[
[4, 0],
[8, 0]
]);
r = multiply(
m,
[
[2, 0, 1],
[4, 0, 1]
]);
assert.deepEqual(
r.valueOf(),
[
[4, 0, 2],
[8, 0, 4]
]);
});
it('should multiply matrix x vector array', function() {
var m = math.matrix([
[2, 0],
[4, 0]
]);
var r = multiply(
m,
[
[2],
[4]
]);
assert.deepEqual(
r.valueOf(),
[
[4],
[8]
]);
});
it ('should NOT squeeze scalar results of matrix * matrix', function () {
var a = math.matrix(
[
[1, 2, 3]
]);
var b = math.matrix(
[
[4],
[5],
[6]
]);
assert.deepEqual(multiply(a, b), math.matrix([[32]]));
});
it ('should NOT squeeze scalar results of matrix * vector', function () {
var a = math.matrix(
[
[1, 2, 3]
]);
var b = [4, 5, 6];
assert.deepEqual(multiply(a, b), math.matrix([32]));
});
it('should throw an error when multiplying matrices with incompatible sizes', function() {
// vector * vector
assert.throws(function () {multiply(math.matrix([1,1], 'dense'), [1, 1, 1]);});
// matrix * matrix
assert.throws(function () {multiply(math.matrix([[1,1]], 'dense'), [[1,1]]);});
assert.throws(function () {multiply(math.matrix([[1,1]], 'dense'), [[1,1], [1,1], [1,1]]);});
// matrix * vector
assert.throws(function () {multiply(math.matrix([[1,1], [1,1]], 'dense'), [1,1,1]);});
// vector * matrix
assert.throws(function () {multiply(math.matrix([1,1,1], 'dense'), [[1,1], [1,1]]);});
});
it('should multiply triangular matrices', function () {
var l = [
[1, 0, 0, 0],
[-0.5, 1, 0, 0],
[0, -0.7, 1, 0],
[0.0666667, -0.4, -0.5714286, 1]
];
var u = [
[240, -2700, 6480, -4200],
[0, -150, 540, -420],
[0, 0, -42, 56],
[0, 0, 0, 4]
];
var r = multiply(l, u);
approx.deepEqual(
r.valueOf(),
[
[240, -2700, 6480, -4200],
[-120, 1200, -2700, 1680],
[0, 105, -420, 350],
[16, -120, 240, -140]
]);
});
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 perform element-wise multiplication if multiplying a matrix and a number', function() {
approx.deepEqual(multiply(a, 3), matrix([[3,6],[9,12]]));
approx.deepEqual(multiply(3, a), matrix([[3,6],[9,12]]));
});
it('should perform matrix multiplication', function () {
approx.deepEqual(multiply(a, b), matrix([[19,22],[43,50]]));
approx.deepEqual(multiply(a, c), matrix([[17],[39]]));
approx.deepEqual(multiply(d, a), matrix([[23,34]]));
approx.deepEqual(multiply(d, b), matrix([[67,78]]));
approx.deepEqual(multiply(d, c), matrix([[61]]));
approx.deepEqual(multiply([[1,2],[3,4]], [[5,6],[7,8]]), [[19,22],[43,50]]);
approx.deepEqual(multiply([1,2,3,4], 2), [2, 4, 6, 8]);
approx.deepEqual(multiply(matrix([1,2,3,4]), 2), matrix([2, 4, 6, 8]));
});
});
describe('Sparse Matrix', function () {
it('should multiply matrix x scalar', function() {
var m = math.matrix([[2, 0], [4, 0]], 'sparse');
var r = multiply(m, 3);
assert.deepEqual(r._size, m._size);
assert.deepEqual(r._values, [6, 12]);
assert.deepEqual(r._index, m._index);
assert.deepEqual(r._ptr, m._ptr);
r = multiply(m, math.complex(3, 3));
assert.deepEqual(r._size, m._size);
assert.deepEqual(r._values, [math.complex(6, 6), math.complex(12, 12)]);
assert.deepEqual(r._index, m._index);
assert.deepEqual(r._ptr, m._ptr);
r = multiply(m, math.bignumber(3));
assert.deepEqual(r._size, m._size);
assert.deepEqual(r._values, [math.bignumber(6), math.bignumber(12)]);
assert.deepEqual(r._index, m._index);
assert.deepEqual(r._ptr, m._ptr);
r = multiply(m, true);
assert.deepEqual(r._size, m._size);
assert.deepEqual(r._values, [2, 4]);
assert.deepEqual(r._index, m._index);
assert.deepEqual(r._ptr, m._ptr);
r = multiply(m, false);
assert.deepEqual(r._size, m._size);
assert.deepEqual(r._values, []);
assert.deepEqual(r._index, []);
assert.deepEqual(r._ptr, [0, 0, 0]);
});
it('should multiply matrix x matrix with zeros', function() {
var m = math.matrix([[2, 0], [4, 0]], 'sparse');
var r = multiply(m, math.matrix([[2, 0], [4, 0]], 'sparse'));
assert.deepEqual(
r.valueOf(),
[
[4, 0],
[8, 0]
]);
r = multiply(m, math.matrix([[2, 0], [4, 0]], 'dense'));
assert.deepEqual(
r.valueOf(),
[
[4, 0],
[8, 0]
]);
});
it('should multiply matrix x matrix', function() {
var m = math.matrix([[1, 2], [3, 4]], 'sparse');
var r = multiply(m, math.matrix([[5, 6], [7, 8]], 'sparse'));
assert.deepEqual(
r.valueOf(),
[
[19, 22],
[43, 50]
]);
r = multiply(m, math.matrix([[5, 6], [7, 8]], 'dense'));
assert.deepEqual(
r.valueOf(),
[
[19, 22],
[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');
var r = multiply(m,
[
[2, 0],
[4, 0]
]);
assert.deepEqual(
r.valueOf(),
[
[4, 0],
[8, 0]
]);
r = multiply(m,
[
[2, 0, 1],
[4, 0, 1]
]);
assert.deepEqual(
r.valueOf(),
[
[4, 0, 2],
[8, 0, 4]
]);
});
it('should multiply matrix x vector array', function() {
var m = math.matrix([[2, 0], [4, 0]], 'sparse');
var r = multiply(m,
[
[2],
[4]
]);
assert.deepEqual(
r.valueOf(),
[
[4],
[8]
]);
});
it ('should NOT squeeze scalar results of matrix * matrix', function () {
var a = math.matrix([[1, 2, 3]], 'sparse');
var b = math.matrix([[4], [5], [6]], 'sparse');
assert.deepEqual(multiply(a, b), math.matrix([[32]], 'sparse'));
});
it ('should NOT squeeze scalar results of matrix * vector', function () {
var a = math.matrix([[1, 2, 3]], 'sparse');
var b = [4, 5, 6];
assert.deepEqual(multiply(a, b), math.matrix([32], 'sparse'));
});
it('should throw an error when multiplying matrices with incompatible sizes', function() {
// vector * vector
assert.throws(function () {math.matrix([1,1], 'sparse').multiply([1, 1, 1]);});
// matrix * matrix
assert.throws(function () {math.matrix([[1,1]], 'sparse').multiply([[1,1]]);});
assert.throws(function () {math.matrix([[1,1]], 'sparse').multiply([[1,1], [1,1], [1,1]]);});
// matrix * vector
assert.throws(function () {math.matrix([[1,1], [1,1]], 'sparse').multiply([1,1,1]);});
// vector * matrix
assert.throws(function () {math.matrix([1,1,1], 'sparse').multiply([[1,1], [1,1]]);});
});
it('should multiply triangular matrices', function () {
var l = math.matrix([
[1, 0, 0, 0],
[-0.5, 1, 0, 0],
[0, -0.7, 1, 0],
[0.0666667, -0.4, -0.5714286, 1]
], 'sparse');
var u = math.matrix([
[240, -2700, 6480, -4200],
[0, -150, 540, -420],
[0, 0, -42, 56],
[0, 0, 0, 4]
], 'sparse');
var r = multiply(l, u);
assert(r.storage(), 'sparse');
approx.deepEqual(
r.valueOf(),
[
[240, -2700, 6480, -4200],
[-120, 1200, -2700, 1680],
[0, 105, -420, 350],
[16, -120, 240, -140]
]);
});
var a = matrix([[1,2],[3,4]], 'sparse');
var b = matrix([[5,6],[7,8]], 'sparse');
var c = matrix([[5],[6]], 'sparse');
var d = matrix([[5,6]], 'sparse');
it('should perform element-wise multiplication if multiplying a matrix and a number', function() {
approx.deepEqual(multiply(a, 3), matrix([[3,6],[9,12]], 'sparse'));
approx.deepEqual(multiply(3, a), matrix([[3,6],[9,12]], 'sparse'));
});
it('should perform matrix multiplication', function () {
approx.deepEqual(multiply(a, b), matrix([[19,22],[43,50]], 'sparse'));
approx.deepEqual(multiply(a, c), matrix([[17],[39]], 'sparse'));
approx.deepEqual(multiply(d, a), matrix([[23,34]], 'sparse'));
approx.deepEqual(multiply(d, b), matrix([[67,78]], 'sparse'));
approx.deepEqual(multiply(d, c), matrix([[61]], 'sparse'));
});
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 () {
it('should multiply matrix x matrix 1220 x 1220, Matrix Market, sparse x sparse', function (done) {
// import matrix
market.import('tools/matrices/fpga_dcop_01.tar.gz', ['fpga_dcop_01/fpga_dcop_01.mtx'])
.then(function (matrices) {
// matrix
var m = matrices[0];
// multiply matrices, used to compare performance in different implementations
math.multiply(m, m);
// indicate test has completed
done();
})
.fail(function (error) {
// indicate test has completed
done(error);
});
});
});
describe ('multiple arguments', function () {
it ('should multiply more than two arguments', function () {
assert.deepEqual(multiply(2, 3, 4), 24);
assert.deepEqual(multiply(2, 3, [5,6]), [30,36]);
});
});
it('should LaTeX multiply', function () {
var expression = math.parse('multiply(2,3)');
assert.equal(expression.toTex(), '\\left(2\\cdot3\\right)');
});
});

View File

@@ -0,0 +1,113 @@
// test norm
var assert = require('assert'),
math = require('../../../index');
describe('norm', function () {
it('should return the absolute value of a boolean', function () {
assert.equal(math.norm(true), 1);
assert.equal(math.norm(true, 10), 1);
assert.equal(math.norm(false), 0);
assert.equal(math.norm(false, 10), 0);
});
it('should return the absolute value of null', function () {
assert.equal(math.norm(null), 0);
assert.equal(math.norm(null, 10), 0);
});
it('should return the absolute value of a number', function () {
assert.equal(math.norm(-4.2), 4.2);
assert.equal(math.norm(-3.5), 3.5);
assert.equal(math.norm(100), 100);
assert.equal(math.norm(0), 0);
assert.equal(math.norm(100, 10), 100);
});
it('should return the absolute value of a big number', function () {
assert.deepEqual(math.norm(math.bignumber(-2.3)), math.bignumber(2.3));
assert.deepEqual(math.norm(math.bignumber('5e500')), math.bignumber('5e500'));
assert.deepEqual(math.norm(math.bignumber('-5e500')), math.bignumber('5e500'));
});
it('should return the norm of a complex number', function () {
assert.equal(math.norm(math.complex(3, -4)), 5);
assert.equal(math.norm(math.complex(1e200, -4e200)), 4.12310562561766e+200);
assert.equal(math.norm(math.complex(-4e200, 1e200)), 4.12310562561766e+200);
});
it('should return the norm of a vector', function () {
// empty vector
assert.equal(math.norm([]), 0.0);
assert.equal(math.norm(math.matrix([])), 0.0);
// p = Infinity
assert.equal(math.norm([1, 2, -3], Number.POSITIVE_INFINITY), 3);
assert.equal(math.norm(math.matrix([1, 2, -3]), Number.POSITIVE_INFINITY), 3);
assert.equal(math.norm([1, 2, -3], 'inf'), 3);
assert.equal(math.norm(math.matrix([1, 2, -3]), 'inf'), 3);
// p = -Infinity
assert.equal(math.norm([1, 2, -3], Number.NEGATIVE_INFINITY), 1);
assert.equal(math.norm(math.matrix([1, 2, -3]), Number.NEGATIVE_INFINITY), 1);
assert.equal(math.norm([1, 2, -3], '-inf'), 1);
assert.equal(math.norm(math.matrix([1, 2, -3]), '-inf'), 1);
// p == 1
assert.equal(math.norm([-3, -4], 1), 7.0);
assert.equal(math.norm(math.matrix([-3, -4]), 1), 7.0);
// p - positive
assert.equal(math.norm([3, 4], 2), 5.0);
assert.equal(math.norm(math.matrix([3, 4]), 2), 5.0);
// p - negative
assert.equal(math.norm([3, 4], -2), 2.4);
assert.equal(math.norm(math.matrix([3, 4]), -2), 2.4);
// missing p (defaults to 2)
assert.equal(math.norm([3, 4]), 5.0);
assert.equal(math.norm(math.matrix([3, 4])), 5.0);
// p == 'fro'
assert.equal(math.norm([3, 4], 'fro'), 5.0);
assert.equal(math.norm(math.matrix([3, 4]), 'fro'), 5.0);
// p == 0
assert.equal(math.norm([3, 4], 0), Number.POSITIVE_INFINITY);
assert.equal(math.norm(math.matrix([3, 4]), 0), Number.POSITIVE_INFINITY);
});
it('should return the norm of a matrix', function () {
// p = 1
assert.equal(math.norm([[1, 2], [3, 4]], 1), 6);
assert.equal(math.norm(math.matrix([[1, 2], [3, 4]]), 1), 6);
assert.equal(math.norm(math.matrix([[1, 2], [3, 4]], 'sparse'), 1), 6);
// p = Infinity
assert.equal(math.norm([[1, 2], [3, 4]], Number.POSITIVE_INFINITY), 7);
assert.equal(math.norm(math.matrix([[1, 2], [3, 4]]), Number.POSITIVE_INFINITY), 7);
assert.equal(math.norm(math.matrix([[1, 2], [3, 4]], 'sparse'), Number.POSITIVE_INFINITY), 7);
assert.equal(math.norm([[1, 2], [3, 4]], 'inf'), 7);
assert.equal(math.norm(math.matrix([[1, 2], [3, 4]]), 'inf'), 7);
assert.equal(math.norm(math.matrix([[1, 2], [3, 4]], 'sparse'), 'inf'), 7);
// p = 'fro'
assert.equal(math.norm([[1, 2], [-3, -4]], 'fro'), math.sqrt(30));
assert.equal(math.norm(math.matrix([[1, 2], [-3, -4]]), 'fro'), math.sqrt(30));
assert.equal(math.norm(math.matrix([[1, 2], [-3, -4]], 'sparse'), 'fro'), math.sqrt(30));
// p - not implemented yet!
assert.throws(function() {
math.norm(math.norm([[1, 2], [3, 4]], 2), 6);
});
});
it('should throw an error in case of invalid number of arguments', function() {
assert.throws(function () {math.norm();}, /TypeError: Too few arguments/);
assert.throws(function () {math.norm(1, 2, 3);}, /TypeError: Too many arguments/);
});
it('should throw an error with a string', function () {
assert.throws(function () {
math.norm('a string');
});
});
it('should LaTeX norm', function () {
var expr1 = math.parse('norm(a)');
var expr2 = math.parse("norm(a,2)");
assert.equal(expr1.toTex(), '\\left\\| a\\right\\|');
assert.equal(expr2.toTex(), '\\mathrm{norm}\\left( a,2\\right)');
});
});

View File

@@ -0,0 +1,210 @@
// test nthRoot
var assert = require('assert');
var approx = require('../../../tools/approx');
var math = require('../../../index');
var matrix = math.matrix;
var sparse = math.sparse;
var unit = math.unit;
var nthRoot = math.nthRoot;
var big = math.bignumber;
var complex = math.complex;
describe('nthRoot', function() {
it('should return the nthRoot of a boolean value', function () {
assert.equal(nthRoot(true), 1);
assert.equal(nthRoot(false), 0);
assert.equal(nthRoot(1,true), 1);
});
it('should return the nthRoot of null', function () {
assert.equal(nthRoot(null), 0);
});
it('should return the nthRoot for numbers', function() {
approx.equal(nthRoot(4), 2);
approx.equal(nthRoot(9), 3);
approx.equal(nthRoot(8, 3), 2);
approx.equal(nthRoot(64, 3), 4);
approx.equal(nthRoot(2, 2.5), 1.31950791077289);
approx.equal(nthRoot(2.5, 2), 1.58113883008419);
approx.equal(nthRoot(0.1+0.2), 0.5477225575051662); // a value containing a round-off error
approx.equal(nthRoot(0, 3), 0);
approx.equal(nthRoot(0, 2), 0);
approx.equal(nthRoot(0.0001, 3), 0.0464158883361278);
});
it('should return the nthRoot for very large numbers', function() {
approx.equal(nthRoot(2e150 * 2e150), 2e150);
approx.equal(nthRoot(Math.pow(2, 1000)), 3.273390607896142e+150);
});
it('should return the nthRoot for small large numbers', function() {
approx.equal(nthRoot(4e-300), 2e-150);
});
it('should return the nthRoot for negative numbers', function() {
approx.equal(nthRoot(-64, 3), -4);
approx.equal(nthRoot(-8, 3), -2);
// Newton's method fails in this particular case: --ericman314
approx.equal(nthRoot(-2, 3), -1.2599210498949);
});
it('should return the nthRoot for negative roots', function() {
approx.equal(nthRoot(64, -3), 0.25);
approx.equal(nthRoot(-64, -3), -0.25);
});
it('should return the nthRoot for zero', function() {
assert.equal(nthRoot(0, 2), 0);
assert.equal(nthRoot(0, -2), Infinity);
});
it('should return the nthRoot for infinity', function() {
approx.equal(nthRoot(Infinity, 2), Infinity);
approx.equal(nthRoot(-Infinity, 3), -Infinity);
approx.equal(nthRoot(Infinity, -3), 0);
});
it('should throw an error when n is zero', function() {
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/);
});
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/);
});
it('should return the nthRoot of bignumbers', function() {
assert.deepEqual(nthRoot(big(4)), big(2));
assert.deepEqual(nthRoot(big(9)), big(3));
assert.deepEqual(nthRoot(big(8), big(3)), big(2));
assert.deepEqual(nthRoot(big(64), big(3)), big(4));
});
it('should return the nthRoot of negative bignumber values', function() {
assert.deepEqual(nthRoot(big(-2), big(3)), big('-1.259921049894873164767210607278228350570251464701507980081975112'));
assert.deepEqual(nthRoot(big(-64), big(3)), big(-4));
});
it('should return the nthRoot of negative bignumber roots', function() {
assert.deepEqual(nthRoot(big(64), big(-3)), big(0.25));
assert.deepEqual(nthRoot(big(-64), big(3)), big(-4));
assert.deepEqual(nthRoot(big(-64), big(-3)), big(-0.25));
});
it('should return the nthRoot for bignumber zero', function() {
assert.deepEqual(nthRoot(big(0), big(2)).toString(), '0');
assert.deepEqual(nthRoot(big(0), big(-2)).toString(), 'Infinity');
});
it('should return the nthRoot for bignumber infinity', function() {
assert.deepEqual(nthRoot(big(Infinity), big(2)).toString(), 'Infinity');
assert.deepEqual(nthRoot(big(-Infinity), big(3)).toString(), '-Infinity');
assert.deepEqual(nthRoot(big(Infinity), big(-3)), big(0));
});
it('should return an array of Complex Roots in Polar form', function() {
var roots = nthRoot(complex("-1"), 6);
var roots1 = [
{r: 1, phi: Math.PI/6},
{r: 1, phi: Math.PI/2},
{r: 1, phi: (5 * Math.PI)/6},
{r: 1, phi: (7 * Math.PI)/6},
{r: 1, phi: (9 * Math.PI)/6},
{r: 1, phi: (11 * Math.PI)/6}
];
roots.forEach(function (value, index, array) {
assert.equal(value.r, roots1[index].r);
assert.equal(value.phi, roots1[index].phi);
});
});
it('should throw an error when used with a complex number and root is less than 0', function() {
assert.throws(function () {nthRoot(complex("-1"), -1);});
});
it('should throw an error when used with a complex number and root is not an integer', function() {
assert.throws(function() {nthRoot(complex("-1 + 2i"), 0.5);});
});
it('should throw an error when used on a unit', function() {
assert.throws(function () {nthRoot(unit('5cm'));});
});
it('should throw an error when used on a string', function() {
assert.throws(function () {nthRoot('text');});
});
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}');
});
});

View File

@@ -0,0 +1,243 @@
// test exp
var assert = require('assert');
var approx = require('../../../tools/approx');
var error = require('../../../lib/error/index');
var math = require('../../../index');
var mathPredictable = math.create({predictable: true});
var bignumber = math.bignumber;
var fraction = math.fraction;
var complex = math.complex;
var matrix = math.matrix;
var unit = math.unit;
var range = math.range;
var pow = math.pow;
describe('pow', function() {
it('should exponentiate a number to the given power', function() {
approx.deepEqual(pow(2,3), 8);
approx.deepEqual(pow(2,4), 16);
approx.deepEqual(pow(-2,2), 4);
approx.deepEqual(pow(3,3), 27);
approx.deepEqual(pow(3,-2), 0.111111111111111);
approx.deepEqual(pow(-3,-2), 0.111111111111111);
approx.deepEqual(pow(3,-3), 0.0370370370370370);
approx.deepEqual(pow(-3,-3), -0.0370370370370370);
approx.deepEqual(pow(2,1.5), 2.82842712474619);
});
it('should exponentiate a negative number to a non-integer power', function() {
approx.deepEqual(pow(-2,1.5), complex(0, -2.82842712474619));
});
it('should exponentiate a negative number to a non-integer power with predictable:true', function() {
var res = mathPredictable.pow(-2,1.5);
assert.equal(typeof res, 'number');
assert(isNaN(res));
});
it('should return a real-valued root if one exists with predictable:true', function() {
approx.equal(mathPredictable.pow(-8, 1/3), -2);
approx.equal(mathPredictable.pow(-8, 2/3), 4);
approx.equal(mathPredictable.pow(-8, 3/3), -8);
approx.equal(mathPredictable.pow(-8, 4/3), 16);
approx.equal(mathPredictable.pow(-8, 5/3), -32);
approx.equal(mathPredictable.pow(-8, -5/3), -0.03125);
approx.equal(mathPredictable.pow(-1, 2/3), 1);
approx.equal(mathPredictable.pow(-1, 50/99), 1);
approx.equal(mathPredictable.pow(-1, 49/99), -1);
approx.equal(mathPredictable.pow(-17, 29/137), -1.8216292479175);
approx.equal(mathPredictable.pow(-1, 0), 1);
approx.equal(mathPredictable.pow(-1, 0.2), -1);
approx.equal(mathPredictable.pow(-1, 1), -1);
approx.equal(mathPredictable.pow(4, 2), 16);
approx.equal(mathPredictable.pow(4, 0.5), 2);
approx.equal(mathPredictable.pow(-4, 2), 16);
assert(isNaN(mathPredictable.pow(-1, 49/100)));
assert(isNaN(mathPredictable.pow(-17, 29/138)));
assert(isNaN(mathPredictable.pow(-17, 3.14159265358979323)));
});
it('should exponentiate booleans to the given power', function() {
assert.equal(pow(true, true), 1);
assert.equal(pow(true, false), 1);
assert.equal(pow(false, true), 0);
assert.equal(pow(false, false), 1);
});
it('should exponentiate mixed numbers and booleans', function() {
assert.equal(pow(2, true), 2);
assert.equal(pow(2, false), 1);
assert.equal(pow(true, 2), 1);
assert.equal(pow(false, 2), 0);
});
it('should exponentiate numbers and null', function () {
assert.equal(pow(1, null), 1);
assert.equal(pow(null, 1), 0);
});
it('should exponentiate bignumbers', function() {
assert.deepEqual(pow(bignumber(2), bignumber(3)), bignumber(8));
assert.deepEqual(pow(bignumber(100), bignumber(500)), bignumber('1e1000'));
assert.deepEqual(pow(bignumber(-1), bignumber(2)), bignumber('1'));
assert.deepEqual(pow(bignumber(2), bignumber(1.5)), bignumber('2.828427124746190097603377448419396157139343750753896146353359476'));
});
it('should exponentiate a negative bignumber to a non-integer power', function() {
approx.deepEqual(pow(bignumber(-2), bignumber(1.5)), complex(0, -2.82842712474619));
approx.deepEqual(pow(-2, bignumber(1.5)), complex(0, -2.82842712474619));
approx.deepEqual(pow(bignumber(-2), 1.5), complex(0, -2.82842712474619));
});
it('should exponentiate a negative bignumber to a non-integer power', function() {
assert.ok(mathPredictable.pow(bignumber(-2), bignumber(1.5)).isNaN());
});
it('should exponentiate mixed numbers and bignumbers', function() {
assert.deepEqual(pow(bignumber(2), 3), bignumber(8));
assert.deepEqual(pow(2, bignumber(3)), bignumber(8));
assert.throws(function () {pow(1/3, bignumber(2))}, /Cannot implicitly convert a number with >15 significant digits to BigNumber/);
assert.throws(function () {pow(bignumber(1), 1/3)}, /Cannot implicitly convert a number with >15 significant digits to BigNumber/);
});
it('should exponentiate mixed booleans and bignumbers', function() {
assert.deepEqual(pow(true, bignumber(3)), bignumber(1));
assert.deepEqual(pow(false, bignumber(3)), bignumber(0));
assert.deepEqual(pow(bignumber(3), false), bignumber(1));
assert.deepEqual(pow(bignumber(3), true), bignumber(3));
});
it('should exponentiate a fraction to an integer power', function() {
assert.deepEqual(math.pow(fraction(3), fraction(2)), fraction(9));
assert.deepEqual(math.pow(fraction(1.5), fraction(2)), fraction(2.25));
assert.deepEqual(math.pow(fraction(1.5), fraction(-2)), fraction(4, 9));
assert.deepEqual(math.pow(fraction(1.5), 2), fraction(2.25));
});
it('should exponentiate a fraction to an non-integer power', function() {
assert.throws(function () {mathPredictable.pow(fraction(3), fraction(1.5))}, /Function pow does not support non-integer exponents for fractions/);
assert.strictEqual(math.pow(fraction(4), 1.5), 8);
assert.strictEqual(math.pow(fraction(4), fraction(1.5)), 8);
});
it('should throw an error if used with wrong number of arguments', function() {
assert.throws(function () {pow(1)}, /TypeError: Too few arguments in function pow/);
assert.throws(function () {pow(1, 2, 3)}, /TypeError: Too many arguments in function pow \(expected: 2, actual: 3\)/);
});
it('should exponentiate a complex number to the given power', function() {
approx.deepEqual(pow(complex(3, 0), 2), complex(9, 0));
approx.deepEqual(pow(complex(0, 2), 2), complex(-4, 0));
approx.deepEqual(pow(complex(-1,-1),complex(-1,-1)), complex('-0.0284750589322119 + 0.0606697332231795i'));
approx.deepEqual(pow(complex(-1,-1),complex(-1,1)), complex('-6.7536199239765713 + 3.1697803027015614i'));
approx.deepEqual(pow(complex(-1,-1),complex(0,-1)), complex('0.0891447921553914 - 0.0321946742909677i'));
approx.deepEqual(pow(complex(-1,-1),complex(0,1)), complex('9.92340022667813 + 3.58383962127501i'));
approx.deepEqual(pow(complex(-1,-1),complex(1,-1)), complex('-0.1213394664463591 - 0.0569501178644237i'));
approx.deepEqual(pow(complex(-1,-1),complex(1,1)), complex('-6.3395606054031211 - 13.5072398479531426i'));
approx.deepEqual(pow(complex(-1,1),complex(-1,-1)), complex('-6.7536199239765713 - 3.1697803027015614i'));
approx.deepEqual(pow(complex(-1,1),complex(-1,1)), complex('-0.0284750589322119 - 0.0606697332231795i'));
approx.deepEqual(pow(complex(-1,1),complex(0,-1)), complex('9.92340022667813 - 3.58383962127501i'));
approx.deepEqual(pow(complex(-1,1),complex(0,1)), complex('0.0891447921553914 + 0.0321946742909677i'));
approx.deepEqual(pow(complex(-1,1),complex(1,-1)), complex('-6.3395606054031211 + 13.5072398479531426i'));
approx.deepEqual(pow(complex(-1,1),complex(1,1)), complex('-0.1213394664463591 + 0.0569501178644237i'));
approx.deepEqual(pow(complex(0,-1),complex(-1,-1)), complex('0.000000000000000 + 0.207879576350762i'));
approx.deepEqual(pow(complex(0,-1),complex(-1,1)), complex('0.000000000000000 + 4.810477380965351i'));
approx.deepEqual(pow(complex(0,-1),complex(1,-1)), complex('0.000000000000000 - 0.207879576350762i'));
approx.deepEqual(pow(complex(0,-1),complex(1,1)), complex('0.000000000000000 - 4.810477380965351i'));
approx.deepEqual(pow(complex(0,1),complex(-1,-1)), complex('0.000000000000000 - 4.810477380965351i'));
approx.deepEqual(pow(complex(0,1),complex(-1,1)), complex('0.000000000000000 - 0.207879576350762i'));
approx.deepEqual(pow(complex(0,1),complex(1,-1)), complex('0.000000000000000 + 4.810477380965351i'));
approx.deepEqual(pow(complex(0,1),complex(1,1)), complex('0.000000000000000 + 0.207879576350762i'));
approx.deepEqual(pow(complex(1,-1),complex(-1,-1)), complex('0.2918503793793073 + 0.1369786269150605i'));
approx.deepEqual(pow(complex(1,-1),complex(-1,1)), complex('0.6589325864505904 + 1.4039396486303144i'));
approx.deepEqual(pow(complex(1,-1),complex(0,-1)), complex('0.428829006294368 - 0.154871752464247i'));
approx.deepEqual(pow(complex(1,-1),complex(0,1)), complex('2.062872235080905 + 0.745007062179724i'));
approx.deepEqual(pow(complex(1,-1),complex(1,-1)), complex('0.2739572538301211 - 0.5837007587586147i'));
approx.deepEqual(pow(complex(1,-1),complex(1,1)), complex('2.8078792972606288 - 1.3178651729011805i'));
approx.deepEqual(pow(complex(1,1),complex(-1,-1)), complex('0.6589325864505904 - 1.4039396486303144i'));
approx.deepEqual(pow(complex(1,1),complex(-1,1)), complex('0.2918503793793073 - 0.1369786269150605i'));
approx.deepEqual(pow(complex(1,1),complex(0,-1)), complex('2.062872235080905 - 0.745007062179724i'));
approx.deepEqual(pow(complex(1,1),complex(0,1)), complex('0.428829006294368 + 0.154871752464247i'));
approx.deepEqual(pow(complex(1,1),complex(1,-1)), complex('2.8078792972606288 + 1.3178651729011805i'));
approx.deepEqual(pow(complex(1,1),complex(1,1)), complex('0.2739572538301211 + 0.5837007587586147i'));
});
it('should exponentiate a complex number to the given bignumber power', function() {
approx.deepEqual(pow(complex(3, 0), math.bignumber(2)), complex(9, 0));
approx.deepEqual(pow(complex(0, 2), math.bignumber(2)), complex(-4, 0));
});
it('should correctly calculate unit ^ number', function() {
assert.equal(pow(unit('4 N'), 2).toString(), "16 N^2");
assert.equal(pow(unit('0.25 m/s'), -0.5).toString(), "2 s^0.5 / m^0.5");
assert.equal(pow(unit('123 hogshead'), 0).toString(), "1");
});
it('should return a cloned value and not affect the argument', function() {
var unit1 = unit('2 m');
var unit2 = pow(unit1, 2);
assert.equal(unit1.toString(), '2 m');
assert.equal(unit2.toString(), '4 m^2');
});
it('should return a valuelessUnit when calculating valuelessUnit ^ number', function() {
assert.equal(pow(unit('kg^0.5 m^0.5 s^-1'), 2).toString(), "(kg m) / s^2");
});
it('should throw an error when doing number ^ unit', function() {
assert.throws(function () {pow(2, unit('5cm'))});
});
it('should throw an error if used with a string', function() {
assert.throws(function () {pow('text', 2)});
assert.throws(function () {pow(2, 'text')});
});
it('should raise a square matrix to the power 2', function() {
var a = [[1,2],[3,4]];
var res = [[7,10],[15,22]];
approx.deepEqual(pow(a, 2), res);
approx.deepEqual(pow(matrix(a), 2), matrix(res));
});
it('should return identity matrix for power 0', function() {
var a = [[1,2],[3,4]];
var res = [[1,0],[0,1]];
approx.deepEqual(pow(a, 0), res);
approx.deepEqual(pow(matrix(a), 0), matrix(res));
});
it('should compute large size of square matrix', function() {
var a = math.eye(30).valueOf();
approx.deepEqual(pow(a, 1000), a);
approx.deepEqual(pow(matrix(a), 1000), matrix(a));
});
it('should throw an error when calculating the power of a non square matrix', function() {
assert.throws(function () {pow([1,2,3,4],2);});
assert.throws(function () {pow([[1,2,3],[4,5,6]],2);});
assert.throws(function () {pow([[1,2,3],[4,5,6]],2);});
});
it('should throw an error when raising a matrix to a non-integer power', function() {
var a = [[1,2],[3,4]];
assert.throws(function () {pow(a, 2.5);});
assert.throws(function () {pow(a, [2,3]);});
});
it('should LaTeX pow', function () {
var expression = math.parse('pow(2,10)');
assert.equal(expression.toTex(), '\\left(2\\right)^{10}');
});
});

View File

@@ -0,0 +1,145 @@
// test round
var assert = require('assert');
var approx = require('../../../tools/approx');
var math = require('../../../index');
var bignumber = math.bignumber;
var fraction = math.fraction;
var matrix = math.matrix;
var sparse = math.sparse;
var round = math.round;
describe('round', function() {
it('should round a number to te given number of decimals', function() {
approx.equal(round(math.pi), 3);
approx.equal(round(math.pi * 1000), 3142);
approx.equal(round(math.pi, 3), 3.142);
approx.equal(round(math.pi, 6), 3.141593);
approx.equal(round(1234.5678, 2), 1234.57);
approx.equal(round(2.135, 2), 2.14);
});
it('should round booleans (yeah, not really useful but it should be supported)', function() {
approx.equal(round(true), 1);
approx.equal(round(false), 0);
approx.equal(round(true, 2), 1);
approx.equal(round(false, 2), 0);
});
it('should round null', function () {
assert.equal(round(null), 0);
assert.equal(round(null, 2), 0);
});
it('should throw an error on invalid type of value', function() {
assert.throws(function () {round(new Date());}, /TypeError: Unexpected type of argument/);
});
it('should throw an error on invalid type of n', function() {
assert.throws(function () {round(math.pi, new Date());}, /TypeError: Unexpected type of argument/);
});
it('should throw an error on invalid value of n', function() {
assert.throws(function () {round(math.pi, -2);}, /Number of decimals in function round must be in te range of 0-15/);
assert.throws(function () {round(math.pi, 20);}, /Number of decimals in function round must be in te range of 0-15/);
assert.throws(function () {round(math.pi, 2.5);}, /Number of decimals in function round must be an integer/);
});
it('should throw an error if used with wrong number of arguments', function() {
assert.throws(function () {round();}, /TypeError: Too few arguments/);
assert.throws(function () {round(1,2,3);}, /TypeError: Too many arguments/);
});
it('should round bignumbers', function() {
assert.deepEqual(round(bignumber(2.7)), bignumber(3));
assert.deepEqual(round(bignumber(2.1)), bignumber(2));
assert.deepEqual(round(bignumber(2.123456), bignumber(3)), bignumber(2.123));
assert.deepEqual(round(bignumber(2.123456), 3), bignumber(2.123));
assert.deepEqual(round(2.1234567, bignumber(3)), bignumber(2.123));
assert.deepEqual(round(true, bignumber(3)), bignumber(1));
assert.deepEqual(round(bignumber(1.23), true), bignumber(1.2));
});
it('should round fractions', function() {
var a = fraction('2/3');
assert(round(a) instanceof math.type.Fraction);
assert.equal(a.toString(), '0.(6)');
assert.equal(round(fraction('2/3')).toString(), '1');
assert.equal(round(fraction('1/3')).toString(), '0');
assert.equal(round(fraction('1/2')).toString(), '1');
});
it('should round real and imag part of a complex number', function() {
assert.deepEqual(round(math.complex(2.2, math.pi)), math.complex(2,3));
});
it('should round a complex number with a bignumber as number of decimals', function() {
assert.deepEqual(round(math.complex(2.157, math.pi), bignumber(2)), math.complex(2.16, 3.14));
});
it('should throw an error if used with a unit', function() {
assert.throws(function () { round(math.unit('5cm')); }, TypeError, 'Function round(unit) not supported');
assert.throws(function () { round(math.unit('5cm'), 2); }, TypeError, 'Function round(unit) not supported');
assert.throws(function () { round(math.unit('5cm'), bignumber(2)); }, TypeError, 'Function round(unit) not supported');
});
it('should convert to a number when used with a string', function() {
assert.strictEqual(round('3.6'), 4);
assert.strictEqual(round('3.12345', '3'), 3.123);
assert.throws(function () {round('hello world'); }, /Cannot convert "hello world" to a number/);
});
it('should round each element in a matrix, array, range', function() {
assert.deepEqual(round(math.range(0,2.1,1/3), 2), math.matrix([0,0.33,0.67,1,1.33,1.67,2]));
assert.deepEqual(round(math.range(0,2.1,1/3)), math.matrix([0,0,1,1,1,2,2]));
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)');
var expr2 = math.parse('round(1.1,2)');
assert.equal(expr1.toTex(), '\\left\\lfloor1.1\\right\\rceil');
assert.equal(expr2.toTex(), '\\mathrm{round}\\left(1.1,2\\right)');
});
});

View File

@@ -0,0 +1,81 @@
// test sign
var assert = require('assert');
var approx = require('../../../tools/approx');
var math = require('../../../index');
var bignumber = math.bignumber;
var fraction = math.fraction;
var complex = math.complex;
describe('sign', function() {
it('should calculate the sign of a boolean', function () {
assert.equal(math.sign(true), 1);
assert.equal(math.sign(false), 0);
});
it('should calculate the sign of null', function () {
assert.equal(math.sign(null), 0);
});
it('should calculate the sign of a number', function() {
assert.equal(math.sign(3), 1);
assert.equal(math.sign(-3), -1);
assert.equal(math.sign(0), 0);
});
it('should calculate the sign of a big number', function() {
assert.deepEqual(math.sign(bignumber(3)), bignumber(1));
assert.deepEqual(math.sign(bignumber(-3)), bignumber(-1));
assert.deepEqual(math.sign(bignumber(0)), bignumber(0));
});
it('should calculate the sign of a fraction', function() {
var a = fraction(0.5);
assert(math.sign(a) instanceof math.type.Fraction);
assert.equal(math.sign(a).toString(), '1');
assert.equal(math.sign(fraction(-0.5)).toString(), '-1');
assert.equal(a.toString(), '0.5');
});
it('should calculate the sign of a complex value', function() {
approx.deepEqual(math.sign(math.complex(2,-3)), math.complex(0.554700196225229, -0.832050294337844));
});
it('should calculate the sign of a unit', function() {
assert.equal(math.sign(math.unit('5 cm')), 1);
assert.equal(math.sign(math.unit('-5 kg')), -1);
assert.equal(math.sign(math.unit('0 mol/s')), 0);
assert.equal(math.sign(math.unit('-283.15 degC')), -1);
assert.equal(math.sign(math.unit('-273.15 degC')), 0);
assert.equal(math.sign(math.unit('-263.15 degC')), 1);
assert.deepEqual(math.sign(math.unit(bignumber(5), 'cm')), bignumber(1));
assert.deepEqual(math.sign(math.unit(bignumber(-5), 'cm')), bignumber(-1));
assert.deepEqual(math.sign(math.unit(fraction(5), 'cm')), fraction(1));
assert.deepEqual(math.sign(math.unit(fraction(-5), 'cm')), fraction(-1));
assert.deepEqual(math.sign(math.unit(complex(3,4), 'mi')), complex(0.6,0.8));
});
it('should throw an error when used with a string', function() {
assert.throws(function () { math.sign("hello world"); });
});
it('should return a matrix of the signs of each elements in the given array', function() {
assert.deepEqual(math.sign([-2,-1,0,1,2]), [-1,-1,0,1,1]);
});
it('should return a matrix of the signs of each elements in the given matrix', function() {
assert.deepEqual(math.sign(math.matrix([-2,-1,0,1,2])), math.matrix([-1,-1,0,1,1]));
});
it('should throw an error in case of invalid number of arguments', function() {
assert.throws(function () {math.sign()}, /TypeError: Too few arguments/);
assert.throws(function () {math.sign(1, 2)}, /TypeError: Too many arguments/);
});
it('should LaTeX sign', function () {
var expression = math.parse('sign(-4)');
assert.equal(expression.toTex(), '\\mathrm{sign}\\left(-4\\right)');
});
});

View File

@@ -0,0 +1,100 @@
// test sqrt
var assert = require('assert');
var approx = require('../../../tools/approx');
var error = require('../../../lib/error/index');
var math = require('../../../index');
var mathPredictable = math.create({predictable: true});
var sqrt = math.sqrt;
var bignumber = math.bignumber;
describe('sqrt', function() {
it('should return the square root of a boolean', function () {
assert.equal(sqrt(true), 1);
assert.equal(sqrt(false), 0);
});
it('should return the square root of null', function () {
assert.equal(sqrt(null), 0);
});
it('should return the square root of a positive number', function() {
assert.equal(sqrt(0), 0);
assert.equal(sqrt(1), 1);
assert.equal(sqrt(4), 2);
assert.equal(sqrt(9), 3);
assert.equal(sqrt(16), 4);
assert.equal(sqrt(25), 5);
});
it('should return the square root of a negative number', function() {
assert.deepEqual(sqrt(-4), math.complex(0, 2));
assert.deepEqual(sqrt(-16), math.complex(0, 4));
});
it('should return the square root of a negative number when predictable:true', function() {
assert.strictEqual(mathPredictable.sqrt(4), 2);
assert(typeof mathPredictable.sqrt(-4), 'number');
assert(isNaN(mathPredictable.sqrt(-4)));
});
it('should return the square root of a positive bignumber', function() {
assert.deepEqual(sqrt(bignumber(0)), bignumber(0));
assert.deepEqual(sqrt(bignumber(1)), bignumber(1));
assert.deepEqual(sqrt(bignumber(4)), bignumber(2));
assert.deepEqual(sqrt(bignumber(9)), bignumber(3));
assert.deepEqual(sqrt(bignumber(16)), bignumber(4));
assert.deepEqual(sqrt(bignumber(25)), bignumber(5));
// validate whether we are really working at high precision
var bigmath = math.create({precision: 100});
assert.deepEqual(bigmath.sqrt(bigmath.bignumber(2)), bigmath.bignumber('1.414213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641573'));
});
it('should return the square root of a negative bignumber', function() {
assert.deepEqual(sqrt(bignumber(-4)), math.complex(0, 2));
});
it('should return the square root of a negative bignumber when predictable:true', function() {
assert.deepEqual(mathPredictable.sqrt(bignumber(4)), bignumber(2));
assert.ok(mathPredictable.sqrt(bignumber(-4)).isNaN());
});
it('should return the square root of a complex number', function() {
assert.deepEqual(sqrt(math.complex(3, -4)), math.complex(2, -1));
assert.deepEqual(sqrt(math.complex(1e10, 1e-10)), math.complex(1e5, 5e-16));
});
it('should return the square root of a unit', function() {
assert.equal(sqrt(math.unit('25 m^2/s^2')).toString(), '5 m / s');
assert.equal(sqrt(math.unit('4 kg')).toString(), '2 kg^0.5');
});
it('should return a Unit with a Complex value when computing the square root of a negative unit', function() {
// Update this when support for complex units is added
//assert.equal(sqrt(math.unit('-25 m^2/s^2')).toString(), 'NaN m / s');
assert.equal(math.format(sqrt(math.unit('-25 m^2/s^2')), 14), '(5i) m / s');
});
it('should throw an error when used with a string', function() {
assert.throws(function () {
sqrt('a string');
});
});
it('should return the square root of each element of a matrix', function() {
assert.deepEqual(sqrt([4,9,16,25]), [2,3,4,5]);
assert.deepEqual(sqrt([[4,9],[16,25]]), [[2,3],[4,5]]);
assert.deepEqual(sqrt(math.matrix([[4,9],[16,25]])), math.matrix([[2,3],[4,5]]));
});
it('should throw an error in case of invalid number of arguments', function() {
assert.throws(function () {sqrt()}, /TypeError: Too few arguments/);
assert.throws(function () {sqrt(1, 2)}, /TypeError: Too many arguments/);
});
it('should LaTeX sqrt', function () {
var expression = math.parse('sqrt(2)');
assert.equal(expression.toTex(), '\\sqrt{2}');
});
});

View File

@@ -0,0 +1,72 @@
// test square
var assert = require('assert');
var math = require('../../../index');
var unit = math.unit;
var bignumber = math.bignumber;
var fraction = math.fraction;
var matrix = math.matrix;
var range = math.range;
var square = math.square;
describe('square', function() {
it('should return the square of a boolean', function () {
assert.equal(square(true), 1);
assert.equal(square(false), 0);
});
it('should return the square of null', function () {
assert.equal(square(null), 0);
});
it('should return the square of a number', function() {
assert.equal(square(4), 16);
assert.equal(square(-2), 4);
assert.equal(square(0), 0);
});
it('should return the square of a big number', function() {
assert.deepEqual(square(bignumber(4)), bignumber(16));
assert.deepEqual(square(bignumber(-2)), bignumber(4));
assert.deepEqual(square(bignumber(0)), bignumber(0));
});
it('should return the square of a fraction', function() {
var a = fraction(0.5);
assert(square(a) instanceof math.type.Fraction);
assert.equal(square(a).toString(), '0.25');
assert.equal(a.toString(), '0.5');
});
it('should throw an error if used with wrong number of arguments', function() {
assert.throws(function () {square()}, /TypeError: Too few arguments/);
assert.throws(function () {square(1, 2)}, /TypeError: Too many arguments/);
});
it('should return the square of a complex number', function() {
assert.deepEqual(square(math.complex('2i')), math.complex('-4'));
assert.deepEqual(square(math.complex('2+3i')), math.complex('-5+12i'));
assert.deepEqual(square(math.complex('2')), math.complex('4'));
});
it('should return the square of a unit', function() {
assert.equal(square(math.unit('4 cm')).toString(), '16 cm^2');
assert.equal(square(math.unit('-2 cm')).toString(), '4 cm^2');
assert.equal(square(math.unit('0 cm')).toString(), '0 cm^2');
});
it('should throw an error when used with a string', function() {
assert.throws(function () {square('text')});
});
it('should return the square of each element in a matrix', function() {
assert.deepEqual(square([2,3,4,5]), [4,9,16,25]);
assert.deepEqual(square(matrix([2,3,4,5])), matrix([4,9,16,25]));
assert.deepEqual(square(matrix([[1,2],[3,4]])), matrix([[1,4],[9,16]]));
});
it('should LaTeX square', function () {
var expression = math.parse('square(4)');
assert.equal(expression.toTex(), '\\left(4\\right)^2');
});
});

View File

@@ -0,0 +1,248 @@
// test subtract
var assert = require('assert');
var approx = require('../../../tools/approx');
var math = require('../../../index');
var bignumber = math.bignumber;
var subtract = math.subtract;
describe('subtract', function() {
it('should subtract two numbers correctly', function() {
assert.deepEqual(subtract(4, 2), 2);
assert.deepEqual(subtract(4, -4), 8);
assert.deepEqual(subtract(-4, -4), 0);
assert.deepEqual(subtract(-4, 4), -8);
assert.deepEqual(subtract(2, 4), -2);
assert.deepEqual(subtract(3, 0), 3);
assert.deepEqual(subtract(0, 3), -3);
assert.deepEqual(subtract(0, 3), -3);
assert.deepEqual(subtract(0, 3), -3);
});
it('should subtract booleans', function() {
assert.equal(subtract(true, true), 0);
assert.equal(subtract(true, false), 1);
assert.equal(subtract(false, true), -1);
assert.equal(subtract(false, false), 0);
});
it('should subtract mixed numbers and booleans', function() {
assert.equal(subtract(2, true), 1);
assert.equal(subtract(2, false), 2);
assert.equal(subtract(true, 2), -1);
assert.equal(subtract(false, 2), -2);
});
it('should subtract numbers and null', function () {
assert.equal(subtract(1, null), 1);
assert.equal(subtract(null, 1), -1);
});
it('should subtract bignumbers', function() {
assert.deepEqual(subtract(bignumber(0.3), bignumber(0.2)), bignumber(0.1));
assert.deepEqual(subtract(bignumber('2.3e5001'), bignumber('3e5000')), bignumber('2e5001'));
assert.deepEqual(subtract(bignumber('1e19'), bignumber('1')), bignumber('9999999999999999999'));
});
it('should subtract mixed numbers and bignumbers', 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/);
});
it('should subtract mixed booleans and bignumbers', function() {
assert.deepEqual(subtract(bignumber(1.1), true), bignumber(0.1));
assert.deepEqual(subtract(bignumber(1.1), false), bignumber(1.1));
assert.deepEqual(subtract(false, bignumber(0.2)), bignumber(-0.2));
assert.deepEqual(subtract(true, bignumber(0.2)), bignumber(0.8));
});
it('should subtract two complex numbers correctly', function() {
assert.deepEqual(subtract(math.complex(3, 2), math.complex(8, 4)), math.complex('-5 - 2i'));
assert.deepEqual(subtract(math.complex(6, 3), math.complex(-2, -2)), math.complex('8 + 5i'));
assert.deepEqual(subtract(math.complex(3, 4), 10), math.complex('-7 + 4i'));
assert.deepEqual(subtract(math.complex(3, 4), -2), math.complex('5 + 4i'));
assert.deepEqual(subtract(math.complex(-3, -4), 10), math.complex('-13 - 4i'));
assert.deepEqual(subtract(10, math.complex(3, 4)), math.complex('7 - 4i'));
assert.deepEqual(subtract(10, math.i), math.complex('10 - i'));
assert.deepEqual(subtract(0, math.i), math.complex('-i'));
assert.deepEqual(subtract(10, math.complex(0, 1)), math.complex('10 - i'));
});
it('should throw an error for mixed complex numbers and big numbers', function() {
assert.deepEqual(subtract(math.complex(3, 4), math.bignumber(10)), math.complex(-7, 4));
assert.deepEqual(subtract(math.bignumber(10), math.complex(3, 4)), math.complex(7, -4));
});
it('should subtract two fractions', function() {
var a = math.fraction(1,3);
assert.equal(subtract(a, math.fraction(1,6)).toString(), '0.1(6)');
assert.equal(a.toString(), '0.(3)');
assert.equal(subtract(math.fraction(3,5), math.fraction(1,5)).toString(), '0.4');
assert.equal(subtract(math.fraction(1), math.fraction(1,3)).toString(), '0.(6)');
});
it('should subtract mixed fractions and numbers', function() {
assert.deepEqual(subtract(1, math.fraction(1,3)), math.fraction(2,3));
assert.deepEqual(subtract(math.fraction(1,3), 1), math.fraction(-2,3));
});
it('should subtract two quantities of the same unit', function() {
approx.deepEqual(subtract(math.unit(5, 'km'), math.unit(100, 'mile')), math.unit(-155.93, 'km'));
assert.deepEqual(subtract(math.unit(math.bignumber(5), 'km'), math.unit(math.bignumber(2), 'km')), math.unit(math.bignumber(3), 'km'));
assert.deepEqual(subtract(math.unit(math.complex(10,10), 'K'), math.unit(math.complex(3,4), 'K')), math.unit(math.complex(7,6), 'K'));
assert.deepEqual(subtract(math.unit(math.complex(10,10), 'K'), math.unit(3, 'K')), math.unit(math.complex(7,10), 'K'));
});
it('should throw an error if subtracting two quantities of different units', function() {
assert.throws(function () {
subtract(math.unit(5, 'km'), math.unit(100, 'gram'));
});
});
it('should throw an error when one of the two units has undefined value', function() {
assert.throws(function () {
subtract(math.unit('km'), math.unit('5gram'));
}, /Parameter x contains a unit with undefined value/);
assert.throws(function () {
subtract(math.unit('5 km'), math.unit('gram'));
}, /Parameter y contains a unit with undefined value/);
});
it('should throw an error if subtracting numbers from units', function() {
assert.throws(function () { subtract(math.unit(5, 'km'), 2); }, TypeError);
assert.throws(function () { subtract(2, math.unit(5, 'km')); }, TypeError);
});
it('should throw an error if subtracting numbers from units', function() {
assert.throws(function () { subtract(math.unit(5, 'km'), bignumber(2)); }, TypeError);
assert.throws(function () { subtract(bignumber(2), math.unit(5, 'km')); }, TypeError);
});
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');});
});
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/);
});
it('should LaTeX subtract', function () {
var expression = math.parse('subtract(2,1)');
assert.equal(expression.toTex(), '\\left(2-1\\right)');
});
});

View File

@@ -0,0 +1,82 @@
// test unary minus
var assert = require('assert');
var math = require('../../../index');
var bignumber = math.bignumber;
var fraction = math.fraction;
var complex = math.complex;
describe('unaryMinus', function() {
it('should return unary minus of a boolean', function () {
assert.equal(math.unaryMinus(true), -1);
assert.equal(math.unaryMinus(false), 0);
});
// TODO: unary minus should return bignumber on boolean input when configured for bignumber
it.skip('should return bignumber unary minus of a boolean', function () {
var bigmath = math.create({number: 'BigNumber'});
assert.deepEqual(bigmath.unaryMinus(true), bigmath.bignumber(-1));
assert.deepEqual(bigmath.unaryMinus(false), bigmath.bignumber(0));
});
it('should return unary minus of null', function () {
assert.equal(math.unaryMinus(null), 0);
});
it('should perform unary minus of a number', function() {
assert.deepEqual(math.unaryMinus(2), -2);
assert.deepEqual(math.unaryMinus(-2), 2);
assert.deepEqual(math.unaryMinus(0), 0);
});
it('should perform unary minus of a big number', function() {
assert.deepEqual(math.unaryMinus(bignumber(2)), bignumber(-2));
assert.deepEqual(math.unaryMinus(bignumber(-2)), bignumber(2));
assert.deepEqual(math.unaryMinus(bignumber(0)).toString(), '0');
});
it('should perform unary minus of a fraction', function() {
var a = fraction(0.5);
assert(math.unaryMinus(a) instanceof math.type.Fraction);
assert.equal(a.toString(), '0.5');
assert.equal(math.unaryMinus(fraction(0.5)).toString(), '-0.5');
assert.equal(math.unaryMinus(fraction(-0.5)).toString(), '0.5');
});
it('should perform unary minus of a complex number', function() {
assert.equal(math.unaryMinus(math.complex(3, 2)), '-3 - 2i');
assert.equal(math.unaryMinus(math.complex(3, -2)), '-3 + 2i');
assert.equal(math.unaryMinus(math.complex(-3, 2)), '3 - 2i');
assert.equal(math.unaryMinus(math.complex(-3, -2)), '3 + 2i');
});
it('should perform unary minus of a unit', function() {
assert.equal(math.unaryMinus(math.unit(5, 'km')).toString(), '-5 km');
assert.equal(math.unaryMinus(math.unit(fraction(2/3), 'km')).toString(), '-2/3 km');
assert.equal(math.unaryMinus(math.unit(complex(2,-4), 'gal')).toString(), '(-2 + 4i) gal');
});
it('should perform element-wise unary minus on a matrix', function() {
a2 = math.matrix([[1,2],[3,4]]);
var a7 = math.unaryMinus(a2);
assert.ok(a7 instanceof math.type.Matrix);
assert.deepEqual(a7.size(), [2,2]);
assert.deepEqual(a7.valueOf(), [[-1,-2],[-3,-4]]);
assert.deepEqual(math.unaryMinus([[1,2],[3,4]]), [[-1,-2],[-3,-4]]);
});
it('should throw an error in case of invalid number of arguments', function() {
assert.throws(function () {math.unaryMinus()}, /TypeError: Too few arguments/);
assert.throws(function () {math.unaryMinus(1, 2)}, /TypeError: Too many arguments/);
});
it('should throw an error in case of invalid type of argument', function() {
assert.throws(function () {math.unaryMinus(new Date())}, /TypeError: Unexpected type of argument/);
});
it('should LaTeX unaryMinus', function () {
var expression = math.parse('unaryMinus(1)');
assert.equal(expression.toTex(), '-\\left(1\\right)');
});
});

View File

@@ -0,0 +1,114 @@
// test unary plus
var assert = require('assert');
var math = require('../../../index');
var error = require('../../../lib/error/index');
var bignumber = math.bignumber;
var fraction = math.fraction;
describe('unaryPlus', function() {
it('should return unary plus of a boolean', function () {
assert.equal(math.unaryPlus(true), 1);
assert.equal(math.unaryPlus(false), 0);
});
it('should return unary plus of null', function () {
assert.equal(math.unaryPlus(null), 0);
});
it.skip('should return bignumber unary plus of a boolean', function () {
var bigmath = math.create({number: 'BigNumber'});
assert.deepEqual(bigmath.unaryPlus(true), bigmath.bignumber(1));
assert.deepEqual(bigmath.unaryPlus(false), bigmath.bignumber(0));
});
// TODO: this is temporary until the test above works again
it('should return bignumber unary plus of a boolean', function () {
var bigmath = math.create({number: 'BigNumber'});
var a = bigmath.unaryPlus(true);
assert(a instanceof math.type.BigNumber);
assert.deepEqual(a.toString(), '1');
var b = bigmath.unaryPlus(false);
assert(b instanceof math.type.BigNumber);
assert.deepEqual(b.toString(), '0');
});
it('should return unary plus on a string', function() {
assert.equal(math.unaryPlus('2'), 2);
assert.equal(math.unaryPlus('-2'), -2);
});
it.skip('should return bignumber unary plus on a string', function() {
var bigmath = math.create({number: 'BigNumber'});
assert.deepEqual(bigmath.unaryPlus('2'), bigmath.bignumber(2));
assert.deepEqual(bigmath.unaryPlus('-2'), bigmath.bignumber(-2));
});
// TODO: this is temporary until the test above works again
it('should return bignumber unary plus on a string', function() {
var bigmath = math.create({number: 'BigNumber'});
var a = bigmath.unaryPlus('2');
assert(a instanceof math.type.BigNumber);
assert.deepEqual(a.toString(), '2');
var b = bigmath.unaryPlus('-2');
assert(b instanceof math.type.BigNumber);
assert.deepEqual(b.toString(), '-2');
});
it('should perform unary plus of a number', function() {
assert.deepEqual(math.unaryPlus(2), 2);
assert.deepEqual(math.unaryPlus(-2), -2);
assert.deepEqual(math.unaryPlus(0), 0);
});
it('should perform unary plus of a big number', function() {
assert.deepEqual(math.unaryPlus(bignumber(2)), bignumber(2));
assert.deepEqual(math.unaryPlus(bignumber(-2)), bignumber(-2));
assert.deepEqual(math.unaryPlus(bignumber(0)).valueOf(), bignumber(0).valueOf());
});
it('should perform unary plus of a fraction', function() {
var a = fraction(0.5);
assert(math.unaryPlus(a) instanceof math.type.Fraction);
assert.equal(a.toString(), '0.5');
assert.equal(math.unaryPlus(fraction(0.5)).toString(), '0.5');
assert.equal(math.unaryPlus(fraction(-0.5)).toString(), '-0.5');
});
it('should perform unary plus of a complex number', function() {
assert.equal(math.unaryPlus(math.complex(3, 2)), '3 + 2i');
assert.equal(math.unaryPlus(math.complex(3, -2)), '3 - 2i');
assert.equal(math.unaryPlus(math.complex(-3, 2)), '-3 + 2i');
assert.equal(math.unaryPlus(math.complex(-3, -2)), '-3 - 2i');
});
it('should perform unary plus of a unit', function() {
assert.equal(math.unaryPlus(math.unit(5, 'km')).toString(), '5 km');
});
it('should perform element-wise unary plus on a matrix', function() {
a2 = math.matrix([[1,2],[3,4]]);
var a7 = math.unaryPlus(a2);
assert.ok(a7 instanceof math.type.Matrix);
assert.deepEqual(a7.size(), [2,2]);
assert.deepEqual(a7.valueOf(), [[1,2],[3,4]]);
assert.deepEqual(math.unaryPlus([[1,2],[3,4]]), [[1,2],[3,4]]);
});
it('should throw an error in case of invalid number of arguments', function() {
assert.throws(function () {math.unaryPlus()}, /TypeError: Too few arguments/);
assert.throws(function () {math.unaryPlus(1, 2)}, /TypeError: Too many arguments/);
});
it('should throw an error in case of invalid type of argument', function() {
assert.throws(function () {math.unaryPlus(new Date())}, /TypeError: Unexpected type of argument/);
});
it('should LaTeX unaryPlus', function () {
var expression = math.parse('unaryPlus(1)');
assert.equal(expression.toTex(), '+\\left(1\\right)');
});
});

View File

@@ -0,0 +1,129 @@
// test xgcd
var assert = require('assert'),
error = require('../../../lib/error/index'),
math = require('../../../index').create({matrix: 'Array'}),
gcd = math.gcd,
xgcd = math.xgcd;
describe('xgcd', function() {
it('should return extended greatest common divisor of two numbers', function() {
// xgcd(36163, 21199) = 1247 => -7(36163) + 12(21199) = 1247
assert.deepEqual([1247, -7, 12], xgcd(36163, 21199));
// xgcd(120, 23) = 1 => -9(120) + 47(23) = 1
assert.deepEqual([1, -9, 47], xgcd(120, 23));
// some unit tests from: https://github.com/sjkaliski/numbers.js/blob/master/test/basic.test.js
assert.deepEqual([5, -3, 5], xgcd(65, 40));
assert.deepEqual([5, 5, -3], xgcd(40, 65));
assert.deepEqual([21, -16, 27], xgcd(1239, 735));
assert.deepEqual([21, 5, -2], xgcd(105, 252));
assert.deepEqual([21, -2, 5], xgcd(252, 105));
});
it ('should calculate xgcd for edge cases around zero', function () {
assert.deepEqual([3, 1, 0], xgcd(3, 0));
assert.deepEqual([3, -1, 0], xgcd(-3, 0));
assert.deepEqual([3, 0, 1], xgcd(0, 3));
assert.deepEqual([3, 0, -1], xgcd(0, -3));
assert.deepEqual([1, 0, 1], xgcd(1, 1));
assert.deepEqual([1, 1, 0], xgcd(1, 0));
assert.deepEqual([1, 0, -1], xgcd(1, -1));
assert.deepEqual([1, 0, 1], xgcd(-1, 1));
assert.deepEqual([1, -1, 0], xgcd(-1, 0));
assert.deepEqual([1, 0, -1], xgcd(-1, -1));
assert.deepEqual([1, 0, 1], xgcd(0, 1));
assert.deepEqual([1, 0, -1], xgcd(0, -1));
assert.deepEqual([0, 0, 0], xgcd(0, 0));
});
it('should calculate xgcd of booleans', function() {
assert.deepEqual(xgcd(true, true), [1, 0, 1]);
assert.deepEqual(xgcd(true, false), [1, 1, 0]);
assert.deepEqual(xgcd(false, true), [1, 0, 1]);
assert.deepEqual(xgcd(false, false), [0, 0, 0]);
});
it('should calculate xgcd of numbers and null', function () {
assert.deepEqual(xgcd(1, null), [1, 1, 0]);
assert.deepEqual(xgcd(null, 1), [1, 0, 1]);
assert.deepEqual(xgcd(null, null), [0, 0, 0]);
});
it('should calculate xgcd for BigNumbers', function() {
assert.deepEqual(xgcd(math.bignumber(65), math.bignumber(40)), [math.bignumber(5), math.bignumber(-3), math.bignumber(5)]);
assert.deepEqual(xgcd(math.bignumber(65), math.bignumber(40)), [math.bignumber(5), math.bignumber(-3), math.bignumber(5)]);
});
it('should calculate xgcd for mixed BigNumbers and Numbers', function() {
assert.deepEqual(xgcd(math.bignumber(65), 40), [math.bignumber(5), math.bignumber(-3), math.bignumber(5)]);
assert.deepEqual(xgcd(65, math.bignumber(40)), [math.bignumber(5), math.bignumber(-3), math.bignumber(5)]);
});
// FIXME: xgcd for negative values
it.skip('should calculate xgcd for edge cases with negative values', function () {
assert.deepEqual([1, -2, 1], xgcd(2, 5));
assert.deepEqual([1, -2, -1], xgcd(2, -5));
assert.deepEqual([1, 2, 1], xgcd(-2, 5));
assert.deepEqual([1, 2, -1], xgcd(-2, -5));
assert.deepEqual([2, 1, 0], xgcd(2, 6));
assert.deepEqual([2, 1, 0], xgcd(2, -6));
assert.deepEqual([2, -1, 0], xgcd(-2, 6));
assert.deepEqual([2, -1, 0], xgcd(-2, -6));
});
it('should find the greatest common divisor of booleans', function() {
assert.deepEqual([1, 0, 1], xgcd(true, true));
assert.deepEqual([1, 1, 0], xgcd(true, false));
assert.deepEqual([1, 0, 1], xgcd(false, true));
assert.deepEqual([0, 0, 0], xgcd(false, false));
});
it('should give same results as gcd', function() {
assert.equal(gcd(1239, 735), xgcd(1239, 735)[0]);
assert.equal(gcd(105, 252), xgcd(105, 252)[0]);
assert.equal(gcd(7, 13), xgcd(7, 13)[0]);
});
it('should return a matrix when configured to use matrices', function() {
var math1 = math.create({matrix: 'Matrix'});
assert.deepEqual(math1.xgcd(65, 40), math.matrix([5, -3, 5]));
var math2 = math.create({matrix: 'Array'});
assert.deepEqual(math2.xgcd(65, 40), [5, -3, 5]);
});
it('should throw an error if used with wrong number of arguments', function() {
assert.throws(function () {xgcd(1)});
assert.throws(function () {xgcd(1, 2, 3)});
});
it('should throw an error for non-integer numbers', function() {
assert.throws(function () {xgcd(2, 4.1); }, /Parameters in function xgcd must be integer numbers/);
assert.throws(function () {xgcd(2.3, 4); }, /Parameters in function xgcd must be integer numbers/);
})
it('should throw an error when used with a complex number', function() {
assert.throws(function () {xgcd(math.complex(1,3),2); }, TypeError, 'Function xgcd(complex, number) not supported');
});
it('should convert to a number when used with a string', function() {
assert.deepEqual(xgcd('65', '40'), [5, -3, 5]);
assert.throws(function () {xgcd(2, 'a'); }, /Cannot convert "a" to a number/);
});
it('should throw an error when used with a unit', function() {
assert.throws(function () { xgcd(math.unit('5cm'), 2); }, TypeError, 'Function xgcd(unit, number) not supported');
});
it('should throw an error when used with a matrix', function() {
assert.throws(function () { xgcd([5,2,3], [25,3,6]); }, TypeError, 'Function xgcd(array, array) not supported');
});
it('should LaTeX xgcd', function () {
var expression = math.parse('xgcd(2,3)');
assert.equal(expression.toTex(), '\\mathrm{xgcd}\\left(2,3\\right)');
});
});

View File

@@ -0,0 +1,221 @@
// test bitAnd
var assert = require('assert'),
math = require('../../../index'),
bignumber = math.bignumber,
bitAnd = math.bitAnd;
describe('bitAnd', function () {
it('should bitwise and two numbers', function () {
assert.equal(bitAnd(53, 131), 1);
assert.equal(bitAnd(2, 3), 2);
assert.equal(bitAnd(-2, 3), 2);
assert.equal(bitAnd(2, -3), 0);
assert.equal(bitAnd(-5, -3), -7);
});
it('should bitwise and booleans', function () {
assert.equal(bitAnd(true, true), 1);
assert.equal(bitAnd(true, false), 0);
assert.equal(bitAnd(false, true), 0);
assert.equal(bitAnd(false, false), 0);
});
it('should bitwise and numbers and null', function () {
assert.equal(math.bitAnd(null, null), 0);
assert.equal(math.bitAnd(null, 1), 0);
assert.equal(math.bitAnd(1, null), 0);
});
it('should bitwise and mixed numbers and booleans', function () {
assert.equal(bitAnd(1, true), 1);
assert.equal(bitAnd(1, false), 0);
assert.equal(bitAnd(true, 1), 1);
assert.equal(bitAnd(false, 1), 0);
});
it('should bitwise and bignumbers', function () {
assert.deepEqual(bitAnd(bignumber(1), bignumber(2)), bignumber(0));
assert.deepEqual(bitAnd(bignumber('-1.0e+31'), bignumber('-1.0e+32')), bignumber('-101273397985285317082036849082368'));
assert.deepEqual(bitAnd(bignumber('1.0e+31'), bignumber('1.0e+32')), bignumber('8726602014714682917961003433984'));
assert.deepEqual(bitAnd(bignumber('-1.0e+31'), bignumber('1.0e+32')), bignumber('91273397985285317082038996566016'));
assert.deepEqual(bitAnd(bignumber('1.0e+31'), bignumber('-1.0e+32')), bignumber('1273397985285317082036849082368'));
assert.deepEqual(bitAnd(bignumber('2.1877409333271352879E+75'), bignumber('-3.220131224058161211554E+42')), bignumber('2187740933327135287899999999999996863578490213829130431270426161710498840576'));
});
it('should bitwise and mixed numbers and bignumbers', function () {
assert.deepEqual(bitAnd(bignumber(1), 2), bignumber(0));
assert.deepEqual(bitAnd(1, bignumber(2)), bignumber(0));
assert.deepEqual(bitAnd(bignumber(7), 9), bignumber(1));
assert.deepEqual(bitAnd(7, bignumber(9)), bignumber(1));
});
it('should bitwise and mixed booleans and bignumbers', function () {
assert.deepEqual(bitAnd(bignumber(1), true), bignumber(1));
assert.deepEqual(bitAnd(bignumber(1), false), bignumber(0));
assert.deepEqual(bitAnd(false, bignumber(3)), bignumber(0));
assert.deepEqual(bitAnd(true, bignumber(3)), bignumber(1));
});
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/);
});
it('should throw an error if the parameters are not integers', function () {
assert.throws(function () {
bitAnd(1.1, 1);
}, /Integers expected in function bitAnd/);
assert.throws(function () {
bitAnd(1, 1.1);
}, /Integers expected in function bitAnd/);
assert.throws(function () {
bitAnd(1.1, 1.1);
}, /Integers expected in function bitAnd/);
assert.throws(function () {
bitAnd(bignumber(1.1), 1);
}, /Integers expected in function bitAnd/);
assert.throws(function () {
bitAnd(1, bignumber(1.1));
}, /Integers expected in function bitAnd/);
assert.throws(function () {
bitAnd(bignumber(1.1), bignumber(1));
}, /Integers expected in function bitAnd/);
assert.throws(function () {
bitAnd(bignumber(1), bignumber(1.1));
}, /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]]);
var a4 = bitAnd(a2, a3);
assert.ok(a4 instanceof math.type.Matrix);
assert.deepEqual(a4.size(), [2,2]);
assert.deepEqual(a4.valueOf(), [[1,2],[3,0]]);
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]]);
});
it('should bitwise and a scalar and a matrix correctly', function () {
assert.deepEqual(bitAnd(12, math.matrix([3,9])), math.matrix([0,8]));
assert.deepEqual(bitAnd(math.matrix([3,9]), 12), math.matrix([0,8]));
});
it('should bitwise and a scalar and an array correctly', function () {
assert.deepEqual(bitAnd(12, [3,9]), [0,8]);
assert.deepEqual(bitAnd([3,9], 12), [0,8]);
});
it('should bitwise and a matrix and an array correctly', function () {
var a = [6,4,28];
var b = math.matrix([13,92,101]);
var c = bitAnd(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 () {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, undefined);}, /TypeError: Unexpected type of argument/);
assert.throws(function () {bitAnd(undefined, true);}, /TypeError: Unexpected type of argument/);
});
it('should LaTeX bitAnd', function () {
var expression = math.parse('bitAnd(4,2)');
assert.equal(expression.toTex(), '\\left(4\\&2\\right)');
});
});

View File

@@ -0,0 +1,69 @@
// test bitNot
var assert = require('assert'),
math = require('../../../index'),
bignumber = math.bignumber,
bitNot = math.bitNot;
describe('bitNot', function () {
it('should return bitwise not of a boolean', function () {
assert.equal(bitNot(true), -2);
assert.equal(bitNot(false), -1);
});
it('should return bitwise not of null', function () {
assert.equal(bitNot(null), -1);
});
it('should perform bitwise not of a number', function () {
assert.deepEqual(bitNot(2), -3);
assert.deepEqual(bitNot(-2), 1);
assert.deepEqual(bitNot(0), -1);
});
it('should perform bitwise not of a bignumber', function() {
assert.deepEqual(bitNot(bignumber(2)), bignumber(-3));
assert.deepEqual(bitNot(bignumber(-2)), bignumber(1));
assert.deepEqual(bitNot(bignumber('1.2345e30')), bignumber('-1234500000000000000000000000001'));
});
it('should throw an error if the parameters are not integers', function () {
assert.throws(function () {
bitNot(1.1);
}, /Integer expected in function bitNot/);
assert.throws(function () {
bitNot(bignumber(1.1));
}, /Integer expected in function bitNot/);
});
it('should throw an error if used with a unit', function() {
assert.throws(function () {bitNot(math.unit('5cm'))}, /TypeError: Unexpected type of argument/);
});
it('should perform element-wise bitwise not on a matrix', function () {
a2 = math.matrix([[1,2],[3,4]]);
var a7 = bitNot(a2);
assert.ok(a7 instanceof math.type.Matrix);
assert.deepEqual(a7.size(), [2,2]);
assert.deepEqual(a7.valueOf(), [[-2,-3],[-4,-5]]);
});
it('should perform element-wise bitwise not on an array', function () {
assert.deepEqual(bitNot([[1,2],[3,4]]), [[-2,-3],[-4,-5]]);
});
it('should throw an error in case of invalid number of arguments', function () {
assert.throws(function () {bitNot()}, /TypeError: Too few arguments/);
assert.throws(function () {bitNot(1, 2)}, /TypeError: Too many arguments/);
});
it('should throw an error in case of invalid type of argument', function () {
assert.throws(function () {bitNot(new Date())}, /TypeError: Unexpected type of argument/);
assert.throws(function () {bitNot(undefined)}, /TypeError: Unexpected type of argument/);
});
it('should LaTeX bitNot', function () {
var expression = math.parse('bitNot(4)');
assert.equal(expression.toTex(), '~\\left(4\\right)');
});
});

View File

@@ -0,0 +1,220 @@
// test bitOr
var assert = require('assert'),
math = require('../../../index'),
bignumber = math.bignumber,
bitOr = math.bitOr;
describe('bitOr', function () {
it('should bitwise or two numbers', function () {
assert.equal(bitOr(53, 131), 183);
assert.equal(bitOr(2, 3), 3);
assert.equal(bitOr(-2, 3), -1);
assert.equal(bitOr(2, -3), -1);
assert.equal(bitOr(-5, -3), -1);
});
it('should bitwise or booleans', function () {
assert.equal(bitOr(true, true), 1);
assert.equal(bitOr(true, false), 1);
assert.equal(bitOr(false, true), 1);
assert.equal(bitOr(false, false), 0);
});
it('should bitwise or numbers and null', function () {
assert.equal(math.bitOr(null, null), 0);
assert.equal(math.bitOr(null, 1), 1);
assert.equal(math.bitOr(1, null), 1);
});
it('should bitwise or mixed numbers and booleans', function () {
assert.equal(bitOr(0, true), 1);
assert.equal(bitOr(0, false), 0);
assert.equal(bitOr(true, 0), 1);
assert.equal(bitOr(false, 0), 0);
});
it('should bitwise or bignumbers', function () {
assert.deepEqual(bitOr(bignumber(1), bignumber(2)), bignumber(3));
assert.deepEqual(bitOr(bignumber('-1.0e+31'), bignumber('-1.0e+32')), bignumber('-8726602014714682917963150917632'));
assert.deepEqual(bitOr(bignumber('1.0e+31'), bignumber('1.0e+32')), bignumber('101273397985285317082038996566016'));
assert.deepEqual(bitOr(bignumber('-1.0e+31'), bignumber('1.0e+32')), bignumber('-1273397985285317082038996566016'));
assert.deepEqual(bitOr(bignumber('1.0e+31'), bignumber('-1.0e+32')), bignumber('-91273397985285317082036849082368'));
});
it('should bitwise or mixed numbers and bignumbers', function () {
assert.deepEqual(bitOr(bignumber(1), 2), bignumber(3));
assert.deepEqual(bitOr(1, bignumber(2)), bignumber(3));
assert.deepEqual(bitOr(bignumber(7), 9), bignumber(15));
assert.deepEqual(bitOr(7, bignumber(9)), bignumber(15));
});
it('should bitwise or mixed booleans and bignumbers', function () {
assert.deepEqual(bitOr(bignumber(1), false), bignumber(1));
assert.deepEqual(bitOr(bignumber(2), true), bignumber(3));
assert.deepEqual(bitOr(false, bignumber(1)), bignumber(1));
assert.deepEqual(bitOr(true, bignumber(2)), bignumber(3));
});
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/);
});
it('should throw an error if the parameters are not integers', function () {
assert.throws(function () {
bitOr(1.1, 1);
}, /Integers expected in function bitOr/);
assert.throws(function () {
bitOr(1, 1.1);
}, /Integers expected in function bitOr/);
assert.throws(function () {
bitOr(1.1, 1.1);
}, /Integers expected in function bitOr/);
assert.throws(function () {
bitOr(bignumber(1.1), 1);
}, /Integers expected in function bitOr/);
assert.throws(function () {
bitOr(1, bignumber(1.1));
}, /Integers expected in function bitOr/);
assert.throws(function () {
bitOr(bignumber(1.1), bignumber(1));
}, /Integers expected in function bitOr/);
assert.throws(function () {
bitOr(bignumber(1), bignumber(1.1));
}, /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]]);
var a4 = bitOr(a2, a3);
assert.ok(a4 instanceof math.type.Matrix);
assert.deepEqual(a4.size(), [2,2]);
assert.deepEqual(a4.valueOf(), [[5,6],[7,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]]);
});
it('should bitwise or a scalar and a matrix correctly', function () {
assert.deepEqual(bitOr(12, math.matrix([3,9])), math.matrix([15,13]));
assert.deepEqual(bitOr(math.matrix([3,9]), 12), math.matrix([15,13]));
});
it('should bitwise or a scalar and an array correctly', function () {
assert.deepEqual(bitOr(12, [3,9]), [15,13]);
assert.deepEqual(bitOr([3,9], 12), [15,13]);
});
it('should bitwise or a matrix and an array correctly', function () {
var a = [6,4,28];
var b = math.matrix([13,92,101]);
var c = bitOr(a, b);
assert.ok(c instanceof math.type.Matrix);
assert.deepEqual(c, math.matrix([15,92,125]));
});
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/);
});
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, 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)');
});
});

View File

@@ -0,0 +1,169 @@
// test bitXor
var assert = require('assert'),
math = require('../../../index'),
matrix = math.matrix,
sparse = math.sparse,
bignumber = math.bignumber,
bitXor = math.bitXor;
describe('bitXor', function () {
it('should xor two numbers', function () {
assert.equal(bitXor(53, 131), 182);
assert.equal(bitXor(2, 3), 1);
assert.equal(bitXor(-2, 3), -3);
assert.equal(bitXor(2, -3), -1);
assert.equal(bitXor(-5, -3), 6);
});
it('should xor booleans', function () {
assert.equal(bitXor(true, true), 0);
assert.equal(bitXor(true, false), 1);
assert.equal(bitXor(false, true), 1);
assert.equal(bitXor(false, false), 0);
});
it('should xor numbers and null', function () {
assert.equal(math.bitXor(null, null), 0);
assert.equal(math.bitXor(null, 1), 1);
assert.equal(math.bitXor(1, null), 1);
});
it('should xor mixed numbers and booleans', function () {
assert.equal(bitXor(0, true), 1);
assert.equal(bitXor(0, false), 0);
assert.equal(bitXor(true, 0), 1);
assert.equal(bitXor(false, 0), 0);
assert.equal(bitXor(true, 1), 0);
assert.equal(bitXor(false, 1), 1);
});
it('should bitwise xor bignumbers', function () {
assert.deepEqual(bitXor(bignumber(1), bignumber(2)), bignumber(3));
assert.deepEqual(bitXor(bignumber('-1.0e+31'), bignumber('-1.0e+32')), bignumber('92546795970570634164073698164736'));
assert.deepEqual(bitXor(bignumber('1.0e+31'), bignumber('1.0e+32')), bignumber('92546795970570634164077993132032'));
assert.deepEqual(bitXor(bignumber('-1.0e+31'), bignumber('1.0e+32')), bignumber('-92546795970570634164077993132032'));
assert.deepEqual(bitXor(bignumber('1.0e+31'), bignumber('-1.0e+32')), bignumber('-92546795970570634164073698164736'));
});
it('should bitwise xor mixed numbers and bignumbers', function () {
assert.deepEqual(bitXor(bignumber(1), 2), bignumber(3));
assert.deepEqual(bitXor(1, bignumber(2)), bignumber(3));
assert.deepEqual(bitXor(bignumber(7), 9), bignumber(14));
assert.deepEqual(bitXor(7, bignumber(9)), bignumber(14));
});
it('should bitwise xor mixed booleans and bignumbers', function () {
assert.deepEqual(bitXor(bignumber(1), true), bignumber(0));
assert.deepEqual(bitXor(bignumber(1), false), bignumber(1));
assert.deepEqual(bitXor(true, bignumber(3)), bignumber(2));
assert.deepEqual(bitXor(false, bignumber(3)), bignumber(3));
});
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/);
});
it('should throw an error if the parameters are not integers', function () {
assert.throws(function () {
bitXor(1.1, 1);
}, /Integers expected in function bitXor/);
assert.throws(function () {
bitXor(1, 1.1);
}, /Integers expected in function bitXor/);
assert.throws(function () {
bitXor(1.1, 1.1);
}, /Integers expected in function bitXor/);
assert.throws(function () {
bitXor(bignumber(1.1), 1);
}, /Integers expected in function bitXor/);
assert.throws(function () {
bitXor(1, bignumber(1.1));
}, /Integers expected in function bitXor/);
assert.throws(function () {
bitXor(bignumber(1.1), bignumber(1));
}, /Integers expected in function bitXor/);
assert.throws(function () {
bitXor(bignumber(1), bignumber(1.1));
}, /Integers expected in function bitXor/);
});
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 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 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 bitwise xor sparse matrix - array', function () {
assert.deepEqual(bitXor(sparse([[1, 2], [3, 4]]), [[5, 6], [7, 8]]), matrix([[4, 4],[4, 12]]));
});
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/);
});
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, 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)');
});
});

View File

@@ -0,0 +1,182 @@
// test leftShift
var assert = require('assert'),
math = require('../../../index'),
matrix = math.matrix,
sparse = math.sparse,
bignumber = math.bignumber,
leftShift = math.leftShift;
describe('leftShift', function () {
it('should left shift a number by a given amount', function () {
assert.equal(leftShift(0, 1000), 0);
assert.equal(leftShift(2, 0), 2);
assert.equal(leftShift(2, 3), 16);
assert.equal(leftShift(2, 4), 32);
assert.equal(leftShift(-2, 2), -8);
assert.equal(leftShift(3, 3), 24);
assert.equal(leftShift(-3, 2), -12);
assert.equal(leftShift(-3, 3), -24);
});
it('should left shift booleans by a boolean amount', function () {
assert.equal(leftShift(true, true), 2);
assert.equal(leftShift(true, false), 1);
assert.equal(leftShift(false, true), 0);
assert.equal(leftShift(false, false), 0);
});
it('should left shift with a mix of numbers and booleans', function () {
assert.equal(leftShift(2, true), 4);
assert.equal(leftShift(2, false), 2);
assert.equal(leftShift(true, 2), 4);
assert.equal(leftShift(false, 2), 0);
});
it('should left shift numbers and null', function () {
assert.equal(leftShift(1, null), 1);
assert.equal(leftShift(null, 1), 0);
});
it('should left shift bignumbers', function () {
assert.deepEqual(leftShift(bignumber(2), bignumber(3)), bignumber(16));
assert.deepEqual(leftShift(bignumber(500), bignumber(100)), bignumber('633825300114114700748351602688000'));
assert.deepEqual(leftShift(bignumber(-1), bignumber(2)), bignumber(-4));
assert.equal(leftShift(bignumber(0), bignumber(-2)).isNaN(), true);
assert.deepEqual(leftShift(bignumber(Infinity), bignumber(2)).toString(), 'Infinity');
assert.equal(leftShift(bignumber(Infinity), bignumber(Infinity)).isNaN(), true);
});
it('should left shift mixed numbers and bignumbers', function () {
assert.deepEqual(leftShift(bignumber(2), 3), bignumber(16));
assert.deepEqual(leftShift(bignumber(500), 100), bignumber('633825300114114700748351602688000'));
assert.deepEqual(leftShift(2, bignumber(3)), bignumber(16));
assert.deepEqual(leftShift(-1, bignumber(2)), bignumber(-4));
assert.deepEqual(leftShift(bignumber(-1), 2), bignumber(-4));
assert.equal(leftShift(bignumber(0), -2).isNaN(), true);
assert.equal(leftShift(bignumber(Infinity), Infinity).isNaN(), true);
});
it('should left shift mixed booleans and bignumbers', function () {
assert.deepEqual(leftShift(true, bignumber(3)), bignumber(8));
assert.deepEqual(leftShift(false, bignumber(3)), bignumber(0));
assert.deepEqual(leftShift(bignumber(3), false), bignumber(3));
assert.deepEqual(leftShift(bignumber(3), true), bignumber(6));
});
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/);
});
it('should throw an error if the parameters are not integers', function () {
assert.throws(function () {
leftShift(1.1, 1);
}, /Integers expected in function leftShift/);
assert.throws(function () {
leftShift(1, 1.1);
}, /Integers expected in function leftShift/);
assert.throws(function () {
leftShift(1.1, 1.1);
}, /Integers expected in function leftShift/);
assert.throws(function () {
leftShift(bignumber(1.1), 1);
}, /Integers expected in function leftShift/);
assert.throws(function () {
leftShift(1, bignumber(1.1));
}, /Integers expected in function leftShift/);
assert.throws(function () {
leftShift(bignumber(1.1), bignumber(1));
}, /Integers expected in function leftShift/);
assert.throws(function () {
leftShift(bignumber(1), bignumber(1.1));
}, /Integers expected in function leftShift/);
});
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]]));
});
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]]));
});
});
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/);
});
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, 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)');
});
});

View File

@@ -0,0 +1,186 @@
// test rightArithShift
var assert = require('assert'),
math = require('../../../index'),
matrix = math.matrix,
sparse = math.sparse,
bignumber = math.bignumber,
rightArithShift = math.rightArithShift;
describe('rightArithShift', function () {
it('should right arithmetically shift a number by a given amount', function () {
assert.equal(rightArithShift(0, 1000), 0);
assert.equal(rightArithShift(2, 0), 2);
assert.equal(rightArithShift(12, 3), 1);
assert.equal(rightArithShift(32, 4), 2);
assert.equal(rightArithShift(-1, 1000), -1);
assert.equal(rightArithShift(-12, 2), -3);
assert.equal(rightArithShift(122, 3), 15);
assert.equal(rightArithShift(-13, 2), -4);
assert.equal(rightArithShift(-13, 3), -2);
});
it('should right arithmetically shift booleans by a boolean amount', function () {
assert.equal(rightArithShift(true, true), 0);
assert.equal(rightArithShift(true, false), 1);
assert.equal(rightArithShift(false, true), 0);
assert.equal(rightArithShift(false, false), 0);
});
it('should right arithmetically shift with a mix of numbers and booleans', function () {
assert.equal(rightArithShift(2, true), 1);
assert.equal(rightArithShift(2, false), 2);
assert.equal(rightArithShift(true, 0), 1);
assert.equal(rightArithShift(true, 1), 0);
assert.equal(rightArithShift(false, 2), 0);
});
it('should right arithmetically shift numbers and null', function () {
assert.equal(rightArithShift(1, null), 1);
assert.equal(rightArithShift(null, 1), 0);
});
it('should right arithmetically shift bignumbers', function () {
assert.deepEqual(rightArithShift(bignumber(17), bignumber(3)), bignumber(2));
assert.deepEqual(rightArithShift(bignumber('633825300114114700748351602688000'), bignumber(100)), bignumber(500));
assert.deepEqual(rightArithShift(bignumber(-17), bignumber(3)), bignumber(-3));
assert.equal(rightArithShift(bignumber(-17), bignumber(-3)).isNaN(), true);
assert.equal(rightArithShift(bignumber(Infinity), bignumber(Infinity)).isNaN(), true);
assert.deepEqual(rightArithShift(bignumber(-Infinity), bignumber(Infinity)), bignumber(-1));
});
it('should right arithmetically shift mixed numbers and bignumbers', function () {
assert.deepEqual(rightArithShift(bignumber(17), 3), bignumber(2));
assert.deepEqual(rightArithShift(bignumber('-633825300114114700748351602688000'), 100), bignumber(-500));
assert.equal(rightArithShift(bignumber(-17), -3).isNaN(), true);
assert.deepEqual(rightArithShift(17, bignumber(3)), bignumber(2));
assert.deepEqual(rightArithShift(-17, bignumber(3)), bignumber(-3));
assert.equal(rightArithShift(-3, bignumber(-17)).isNaN(), true);
assert.deepEqual(rightArithShift(bignumber(-Infinity), Infinity), bignumber(-1));
assert.equal(rightArithShift(bignumber(Infinity), Infinity).isNaN(), true);
assert.equal(rightArithShift(Infinity, bignumber(Infinity)).isNaN(), true);
});
it('should right arithmetically shift mixed booleans and bignumbers', function () {
assert.deepEqual(rightArithShift(true, bignumber(0)), bignumber(1));
assert.deepEqual(rightArithShift(false, bignumber('1000000')), bignumber(0));
assert.deepEqual(rightArithShift(bignumber(3), false), bignumber(3));
assert.deepEqual(rightArithShift(bignumber(3), true), bignumber(1));
});
it('should throw an error if the parameters are not integers', function () {
assert.throws(function () {
rightArithShift(1.1, 1);
}, /Integers expected in function rightArithShift/);
assert.throws(function () {
rightArithShift(1, 1.1);
}, /Integers expected in function rightArithShift/);
assert.throws(function () {
rightArithShift(1.1, 1.1);
}, /Integers expected in function rightArithShift/);
assert.throws(function () {
rightArithShift(bignumber(1.1), 1);
}, /Integers expected in function rightArithShift/);
assert.throws(function () {
rightArithShift(1, bignumber(1.1));
}, /Integers expected in function rightArithShift/);
assert.throws(function () {
rightArithShift(bignumber(1.1), bignumber(1));
}, /Integers expected in function rightArithShift/);
assert.throws(function () {
rightArithShift(bignumber(1), bignumber(1.1));
}, /Integers expected in function rightArithShift/);
});
it('should throw an error if used with a unit', function() {
assert.throws(function () {rightArithShift(math.unit('5cm'), 2)}, /TypeError: Unexpected type of argument/);
assert.throws(function () {rightArithShift(2, math.unit('5cm'))}, /TypeError: Unexpected type of argument/);
assert.throws(function () {rightArithShift(math.unit('2cm'), math.unit('5cm'))}, /TypeError: Unexpected type of argument/);
});
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]]));
});
});
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 () {
assert.throws(function () {rightArithShift(1)}, /TypeError: Too few arguments/);
assert.throws(function () {rightArithShift(1, 2, 3)}, /TypeError: Too many arguments/);
});
it('should throw an error in case of invalid type of arguments', function () {
assert.throws(function () {rightArithShift(new Date(), true)}, /TypeError: Unexpected type of argument/);
assert.throws(function () {rightArithShift(true, new Date())}, /TypeError: Unexpected type of argument/);
assert.throws(function () {rightArithShift(true, undefined)}, /TypeError: Unexpected type of argument/);
assert.throws(function () {rightArithShift(undefined, true)}, /TypeError: Unexpected type of argument/);
});
it('should LaTeX rightArithShift', function () {
var expression = math.parse('rightArithShift(3,2)');
assert.equal(expression.toTex(), '\\left(3>>2\\right)');
});
});

View File

@@ -0,0 +1,149 @@
// test rightLogShift
var assert = require('assert'),
math = require('../../../index'),
matrix = math.matrix,
sparse = math.sparse,
rightLogShift = math.rightLogShift;
describe('rightLogShift', function () {
it('should right logically shift a number by a given amount', function () {
assert.equal(rightLogShift(0, 1000), 0);
assert.equal(rightLogShift(2, 0), 2);
assert.equal(rightLogShift(12, 3), 1);
assert.equal(rightLogShift(32, 4), 2);
assert.equal(rightLogShift(-1, 1000), 16777215);
assert.equal(rightLogShift(-12, 2), 1073741821);
assert.equal(rightLogShift(122, 3), 15);
assert.equal(rightLogShift(-13, 2), 1073741820);
assert.equal(rightLogShift(-13, 3), 536870910);
});
it('should right logically shift booleans by a boolean amount', function () {
assert.equal(rightLogShift(true, true), 0);
assert.equal(rightLogShift(true, false), 1);
assert.equal(rightLogShift(false, true), 0);
assert.equal(rightLogShift(false, false), 0);
});
it('should right logically shift with a mix of numbers and booleans', function () {
assert.equal(rightLogShift(2, true), 1);
assert.equal(rightLogShift(2, false), 2);
assert.equal(rightLogShift(true, 0), 1);
assert.equal(rightLogShift(true, 1), 0);
assert.equal(rightLogShift(false, 2), 0);
});
it('should right logically shift numbers and null', function () {
assert.equal(rightLogShift(1, null), 1);
assert.equal(rightLogShift(null, 1), 0);
});
it('should throw an error if the parameters are not integers', function () {
assert.throws(function () {
rightLogShift(1.1, 1);
}, /Integers expected in function rightLogShift/);
assert.throws(function () {
rightLogShift(1, 1.1);
}, /Integers expected in function rightLogShift/);
assert.throws(function () {
rightLogShift(1.1, 1.1);
}, /Integers expected in function rightLogShift/);
});
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/);
});
describe('Array', function () {
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]]));
});
});
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/);
});
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, undefined);}, /TypeError: Unexpected type of argument/);
assert.throws(function () {rightLogShift(undefined, true);}, /TypeError: Unexpected type of argument/);
});
it('should LaTeX rightLogShift', function () {
var expression = math.parse('rightLogShift(1,2)');
assert.equal(expression.toTex(), '\\left(1>>>2\\right)');
});
});

View File

@@ -0,0 +1,44 @@
var assert = require('assert'),
error = require('../../../lib/error/index'),
math = require('../../../index'),
bellNumbers = math.bellNumbers;
describe('bellNumbers', function() {
it('should calculate the number of partitions of a set', function() {
assert.equal(bellNumbers(3), 5);
assert.equal(bellNumbers(0), 1);
assert.equal(bellNumbers(8), 4140);
});
it('should calculate the bellNumbers of n items with BigNumbers', function(){
assert.deepEqual(bellNumbers(math.bignumber(2)), math.bignumber(2));
assert.deepEqual(bellNumbers(math.bignumber(3)), math.bignumber(5));
});
it('should not work with non-integer and negative input', function() {
assert.throws(function() {bellNumbers(0.5)}, TypeError);
assert.throws(function() {bellNumbers(-1)}, TypeError);
assert.throws(function() {bellNumbers(math.bignumber(-3))}, TypeError);
assert.throws(function() {bellNumbers(math.bignumber(3.5))}, TypeError);
});
it('should throw an error in case of non-integer input', function() {
assert.throws(function() {bellNumbers(5.2)}, /Non-negative integer value expected/);
});
it('should throw an error in case of negative input', function() {
assert.throws(function() {bellNumbers(-2)}, /Non-negative integer value expected/);
});
it('should throw an error in case of wrong number or type of arguments', function() {
assert.throws(function() {bellNumbers(5, 3, 2)});
assert.throws(function() {bellNumbers(true, "hello world")});
});
it('should LaTeX bellNumbers', function () {
var expression = math.parse('bellNumbers(3)');
assert.equal(expression.toTex(), '\\mathrm{B}_{3}');
});
});

View File

@@ -0,0 +1,44 @@
var assert = require('assert'),
error = require('../../../lib/error/index'),
math = require('../../../index'),
catalan = math.catalan;
describe('catalan', function() {
it('should calculate the nth catalan number', function() {
assert.equal(catalan(3), 5);
assert.equal(catalan(0), 1);
assert.equal(catalan(8), 1430);
});
it('should calculate the nth catalan number with BigNumbers', function(){
assert.deepEqual(catalan(math.bignumber(7)), math.bignumber(429));
assert.deepEqual(catalan(math.bignumber(13)), math.bignumber(742900));
});
it('should not work with non-integer and negative input', function() {
assert.throws(function() {catalan(0.5)}, TypeError);
assert.throws(function() {catalan(-1)}, TypeError);
assert.throws(function() {catalan(math.bignumber(-3))}, TypeError);
assert.throws(function() {catalan(math.bignumber(3.5))}, TypeError);
});
it('should throw an error in case of non-integer input', function() {
assert.throws(function() {catalan(5.2)}, /Non-negative integer value expected/);
});
it('should throw an error in case of negative input', function() {
assert.throws(function() {catalan(-2)}, /Non-negative integer value expected/);
});
it('should throw an error in case of wrong number or type of arguments', function() {
assert.throws(function() {catalan(5, 3, 2)});
assert.throws(function() {catalan(true, "hello world")});
});
it('should LaTeX catalan', function () {
var expression = math.parse('catalan(3)');
assert.equal(expression.toTex(), '\\mathrm{C}_{3}');
});
});

View File

@@ -0,0 +1,34 @@
var assert = require('assert');
var error = require('../../../lib/error/index');
var math = require('../../../index');
var composition = math.composition;
describe('composition', function() {
it('should calculate the number of ways to compose a set of n objects into k non-empty subsets', function() {
assert.equal(composition(5,3), 6);
assert.equal(composition(1,1), 1);
assert.equal(composition(8,3), 21);
});
it('should calculate the composition of n items taken k at a time with BigNumbers', function(){
assert.deepEqual(composition(math.bignumber(7), math.bignumber(5)), math.bignumber(15));
assert.deepEqual(composition(math.bignumber(70), math.bignumber(3)), math.bignumber(2346));
assert.deepEqual(composition(math.bignumber(56), math.bignumber(11)), math.bignumber(29248649430));
});
it('should not work with non-integer and negative input', function() {
assert.throws(function() {composition(0.5, 3)}, /TypeError: Positive integer value expected in function composition/);
assert.throws(function() {composition(-2, 3)}, /TypeError: Positive integer value expected in function composition/);
assert.throws(function() {composition(6, -2)}, /TypeError: Positive integer value expected in function composition/);
assert.throws(function() {composition(3, 5)}, /TypeError: k must be less than or equal to n in function composition/);
assert.throws(function() {composition(math.bignumber(3), math.bignumber(5))}, /TypeError: k must be less than or equal to n in function composition/);
assert.throws(function() {composition(math.bignumber(3.5), math.bignumber(-3))}, /TypeError: Positive integer value expected in function composition/);
assert.throws(function() {composition(math.bignumber(3.5), 0.25)}, /TypeError: Positive integer value expected in function composition/);
});
it('should not work with the wrong number or type of arguments', function() {
assert.throws(function() {composition(5, 3, 2)});
assert.throws(function() {composition(true, "hello world")});
});
});

View File

@@ -0,0 +1,39 @@
var assert = require('assert'),
error = require('../../../lib/error/index'),
math = require('../../../index'),
stirlingS2 = math.stirlingS2;
describe('stirlingS2', function() {
it('should calculate the number of ways to partition a set of n objects into k non-empty subsets', function() {
assert.equal(stirlingS2(5,3), 25);
assert.equal(stirlingS2(0,0), 1);
assert.equal(stirlingS2(8,7), 28);
});
it('should calculate the stirlingS2 of n items taken k at a time with BigNumbers', function(){
assert.deepEqual(stirlingS2(math.bignumber(7), math.bignumber(5)),math.bignumber(140));
assert.deepEqual(stirlingS2(math.bignumber(8), math.bignumber(6)),math.bignumber(266));
});
it('should not work with non-integer and negative input', function() {
assert.throws(function() {stirlingS2(0.5, 3)}, /Non-negative integer value expected/);
assert.throws(function() {stirlingS2(-2, 3)}, /Non-negative integer value expected/);
assert.throws(function() {stirlingS2(3, 5)}, /k must be less than or equal to n in function stirlingS2/);
assert.throws(function() {stirlingS2(math.bignumber(3), math.bignumber(5))}, /k must be less than or equal to n in function stirlingS2/);
assert.throws(function() {stirlingS2(math.bignumber(3.5), math.bignumber(-3))}, /Non-negative integer value expected/);
assert.throws(function() {stirlingS2(math.bignumber(3.5), 1/3)}, /Non-negative integer value expected/);
});
it('should not work with the wrong number or type of arguments', function() {
assert.throws(function() {stirlingS2(5, 3, 2)});
assert.throws(function() {stirlingS2(true, "hello world")});
});
it('should LaTeX stirlingS2', function () {
var expression = math.parse('stirlingS2(3,2)');
assert.equal(expression.toTex(), '\\mathrm{S}\\left(3,2\\right)');
});
});

View File

@@ -0,0 +1,78 @@
var assert = require('assert');
var approx = require('../../../tools/approx');
var math = require('../../../index');
var arg = math.arg;
describe('arg', function() {
it('should compute the argument of a boolean', function () {
assert.equal(arg(true), 0);
assert.equal(arg(false), 0);
});
it('should compute the argument of null', function () {
assert.equal(arg(null), 0);
});
it('should compute the argument of a number', function () {
assert.equal(arg(1), 0);
assert.equal(arg(2), 0);
assert.equal(arg(0), 0);
approx.equal(arg(-2), 3.141592653589793);
});
it('should compute the argument of a bignumber', function () {
assert.deepEqual(arg(math.bignumber(1)), math.bignumber(0));
assert.deepEqual(arg(math.bignumber(-2)),
math.bignumber('3.141592653589793238462643383279502884197169399375105820974944592'));
});
it('should compute the argument of a complex number correctly', function() {
assert.equal(arg(math.complex('0')) / math.pi, 0);
assert.equal(arg(math.complex('1 + 0i')) / math.pi, 0);
assert.equal(arg(math.complex('1 + i')) / math.pi, 0.25);
assert.equal(arg(math.complex('0 + i')) / math.pi, 0.5);
assert.equal(arg(math.complex('-1 + i')) / math.pi, 0.75);
assert.equal(arg(math.complex('-1 + 0i')) / math.pi, 1);
assert.equal(arg(math.complex('-1 - i')) / math.pi, -0.75);
assert.equal(arg(math.complex('0 - i')) / math.pi, -0.5);
assert.equal(arg(math.complex('1 - i')) / math.pi, -0.25);
assert.equal(arg(math.i) / math.pi, 0.5);
});
it('should calculate the argument for each element in a matrix', function() {
assert.deepEqual(math.divide(arg([
math.i, math.unaryMinus(math.i), math.add(1,math.i)
]), math.pi), [
0.5, -0.5, 0.25
]);
assert.deepEqual(math.matrix(math.divide(arg([
math.i, math.unaryMinus(math.i), math.add(1,math.i)
]), math.pi)).valueOf(), [
0.5, -0.5, 0.25
]);
});
it('should compute the argument of a real number correctly', function() {
assert.equal(arg(2) / math.pi, 0);
assert.equal(arg(-2) / math.pi, 1);
});
it('should throw an error if used with a string', function() {
assert.throws(function () {arg('string')});
});
it('should throw an error if used with a unit', function() {
assert.throws(function () {arg(math.unit('5cm'))});
});
it('should throw an error in case of invalid number of arguments', function() {
assert.throws(function () {arg()}, /TypeError: Too few arguments/);
assert.throws(function () {arg(1, 2)}, /TypeError: Too many arguments/);
});
it('should LaTeX arg', function () {
var expression = math.parse('arg(1+i)');
assert.equal(expression.toTex(), '\\arg\\left(1+ i\\right)');
});
});

View File

@@ -0,0 +1,56 @@
var assert = require('assert');
var math = require('../../../index');
var conj = math.conj;
describe('conj', function() {
it('should compute the conjugate of a boolean', function () {
assert.strictEqual(conj(true), 1);
assert.strictEqual(conj(false), 0);
});
it('should compute the conjugate of null', function () {
assert.strictEqual(conj(null), 0);
});
it('should compute the conjugate of a number', function () {
assert.equal(conj(1), 1);
assert.equal(conj(2), 2);
assert.equal(conj(0), 0);
assert.equal(conj(-2), -2);
});
it('should compute the conjugate of a bignumber', function () {
assert.deepEqual(conj(math.bignumber(2)), math.bignumber(2));
});
it('should calculate the conjugate of a complex number correctly', function() {
assert.equal(conj(math.complex('2 + 3i')).toString(), '2 - 3i');
assert.equal(conj(123).toString(), '123');
assert.equal(conj(math.complex('2 - 3i')).toString(), '2 + 3i');
assert.equal(conj(math.complex('2')).toString(), '2');
assert.equal(conj(math.complex('-4i')).toString(), '4i');
assert.equal(conj(math.i).toString(), '-i');
});
it('should calculate the conjugate for each element in a matrix', function() {
assert.equal(math.format(conj([math.complex('2+3i'), math.complex('3-4i')])),
'[2 - 3i, 3 + 4i]');
assert.equal(conj(math.matrix([math.complex('2+3i'), math.complex('3-4i')])).toString(),
'[2 - 3i, 3 + 4i]');
});
it('should throw an error when called with an unsupported type of argument', function() {
assert.throws(function () {conj(new Date())}, /TypeError: Unexpected type of argument/);
assert.throws(function () {conj(math.unit('5cm'))}, /TypeError: Unexpected type of argument/);
});
it('should throw an error in case of invalid number of arguments', function() {
assert.throws(function () {conj()}, /TypeError: Too few arguments/);
assert.throws(function () {conj(1, 2)}, /TypeError: Too many arguments/);
});
it('should LaTeX conj', function () {
var expression = math.parse('conj(1+i)');
assert.equal(expression.toTex(), '\\left(1+ i\\right)^*');
});
});

View File

@@ -0,0 +1,54 @@
var assert = require('assert');
var math = require('../../../index');
describe('im', function() {
it('should return the imaginary part of a complex number', function() {
assert.equal(math.im(math.complex(2,3)), 3);
assert.equal(math.im(math.complex(-2,-3)), -3);
assert.equal(math.im(math.i), 1);
});
it('should return the imaginary part of a real number', function() {
assert.equal(math.im(2), 0);
});
it('should return the imaginary part of a big number', function() {
assert.deepEqual(math.im(math.bignumber(2)), math.bignumber(0));
});
it('should return the imaginary part of a boolean', function() {
assert.equal(math.im(true), 0);
assert.equal(math.im(false), 0);
});
it('should return the imaginary part of null', function() {
assert.equal(math.im(null), 0);
});
it('should return the imaginary part of a boolean', function() {
assert.equal(math.im(true), 0);
assert.equal(math.im(false), 0);
});
it('should return the imaginary part for each element in a matrix', function() {
assert.deepEqual(math.im([2, math.complex('3-6i')]), [0, -6]);
assert.deepEqual(math.im(math.matrix([2, math.complex('3-6i')])).valueOf(), [0, -6]);
});
it('should throw an error when called with an unsupported type of argument', function() {
assert.throws(function () {math.im(new Date())}, /TypeError: Unexpected type of argument/);
assert.throws(function () {math.im(math.unit('5cm'))}, /TypeError: Unexpected type of argument/);
});
it('should throw an error in case of invalid number of arguments', function() {
assert.throws(function () {math.im()}, /TypeError: Too few arguments/);
assert.throws(function () {math.im(1, 2)}, /TypeError: Too many arguments/);
});
it('should LaTeX im', function () {
var expression = math.parse('im(1+i)');
assert.equal(expression.toTex(), '\\Im\\left\\lbrace1+ i\\right\\rbrace');
});
});

View File

@@ -0,0 +1,49 @@
var assert = require('assert');
var math = require('../../../index');
describe('re', function() {
it('should return the real part of a complex number', function() {
assert.equal(math.re(math.complex(2,3)), 2);
assert.equal(math.re(math.complex(-2,-3)), -2);
assert.equal(math.re(math.i), 0);
});
it('should return the real part of a real number', function() {
assert.equal(math.re(2), 2);
});
it('should return the real part of a big number', function() {
assert.deepEqual(math.re(math.bignumber(2)), math.bignumber(2));
});
it('should return the real part of a boolean', function() {
assert.strictEqual(math.re(true), 1);
assert.strictEqual(math.re(false), 0);
});
it('should return the real part of null', function() {
assert.strictEqual(math.re(null), 0);
});
it('should return the real part for each element in a matrix', function() {
assert.deepEqual(math.re([2, math.complex('3-6i')]), [2, 3]);
assert.deepEqual(math.re(math.matrix([2, math.complex('3-6i')])).valueOf(), [2, 3]);
});
it('should throw an error when called with an unsupported type of argument', function() {
assert.throws(function () {math.re(new Date())}, /TypeError: Unexpected type of argument/);
assert.throws(function () {math.re(math.unit('5cm'))}, /TypeError: Unexpected type of argument/);
});
it('should throw an error in case of invalid number of arguments', function() {
assert.throws(function () {math.re()}, /TypeError: Too few arguments/);
assert.throws(function () {math.re(1, 2)}, /TypeError: Too many arguments/);
});
it('should LaTeX re', function () {
var expression = math.parse('re(1+i)');
assert.equal(expression.toTex(), '\\Re\\left\\lbrace1+ i\\right\\rbrace');
});
});

View File

@@ -0,0 +1,92 @@
var assert = require('assert');
var error = require('../../../lib/error/index');
var math = require('../../../index');
describe('distance', function() {
it('should calculate the distance of two 2D points', function() {
assert.equal(math.distance([0, 0], [10, 10]), 14.142135623730951);
assert.equal(math.distance(math.matrix([0,0]),math.matrix([10,10])), 14.142135623730951);
assert.equal(math.distance(math.matrix([0,0,0]),math.matrix([10,10,0])), 14.142135623730951);
assert.equal(math.distance({pointOneX: 0, pointOneY: 0}, {pointTwoX: 10, pointTwoY: 10}), 14.142135623730951);
});
it('should calculate distance between two 3d points', function(){
assert.equal(math.distance([4, 5, 8], [2, 7, 9]), 3);
assert.equal(math.distance(math.matrix([0, 0, 0]), math.matrix([10, 10, 0])), 14.142135623730951);
assert.equal(math.distance(math.matrix([0.31, 0.2, -0.21]), [0.4234, -0.212, -0.2342]), 0.42800607472324503);
assert.equal(math.distance([67435, 654667, 3545567], [53467, 34567, 654356]), 2956995.1236931384);
assert.equal(math.distance([-21, -230, -2141], math.matrix([-1234, -3122, -1242])), 3262.396971553278);
assert.equal(math.distance({pointOneX: 4, pointOneY: 5, pointOneZ: 8}, {pointTwoX: 2, pointTwoY: 7, pointTwoZ: 9}), 3);
});
it('should calculate distance for inputs passed as objects', function(){
assert.deepEqual(math.distance({pointX: 1, pointY: 4}, {lineOnePtX: 6, lineOnePtY: 3}, {lineTwoPtX: 2, lineTwoPtY: 8}), 2.720549372624744);
assert.deepEqual(math.distance({pointX: 10, pointY: 10}, {xCoeffLine: 8, yCoeffLine: 1, constant: 3}), 11.535230316796387);
assert.equal(math.distance({pointOneX: 0, pointOneY: 0}, {pointTwoX: 10, pointTwoY: 10}), 14.142135623730951);
assert.throws(function() {math.distance({pointX: 1, pointY: 4}, {lineOnePtX: 'l', lineOnePtY: 3}, {lineTwoPtX: 2, lineTwoPtY: 8})}, TypeError);
assert.equal(math.distance({pointOneX: 4, pointOneY: 5, pointOneZ: 8}, {pointTwoX: 2, pointTwoY: 7, pointTwoZ: 9}), 3);
});
it('should calculate distance for all non-zero values', function() {
assert.equal(math.distance([1, 1], [10,10]), 12.727922061357855);
assert.equal(math.distance([-1, -1], [10,10]), 15.556349186104045);
assert.equal(math.distance(math.matrix([-1, 8]), [5,10]), 6.324555320336759);
assert.equal(math.distance([-100, 60], [0,500]), 451.22056690713913);
assert.equal(math.distance([-100.78, 60.04], [0.3,500.09]), 451.5098768576386);
assert.equal(math.distance([74, -34, -0.5], math.matrix([34, 100, -4.33])), 139.89520685141431);
assert.deepEqual(math.distance([1, -1, -1], [2, 2, 0.1, 1, 2, 2]), 1.3437096247164249);
});
it('should throw an error for incompatible parameter types', function() {
assert.throws(function() {math.distance(0.5)}, TypeError);
assert.throws(function() {math.distance('1')}, TypeError);
assert.throws(function() {math.distance(["abc", "def"], [1, 3])}, TypeError);
assert.throws(function() {math.distance(['2', '3'], math.matrix(["a", "c"]), [1, -0.445364786543434])}, TypeError);
assert.throws(function() {math.distance({pointX: 1, pointY: 4}, {lineOnePtX: 'l', lineOnePtY: 3}, {lineTwoPtX: 2, lineTwoPtY: 8})}, TypeError);
assert.throws(function() {math.distance({wrongkeyname: 2, english: 3, pointZ: 1}, {x0: 1, y0: 1, z0: 2, a: 5, b: 0, c: 1})}, TypeError);
});
it('should throw an error for unsupported number of parameters', function() {
assert.throws(function() {math.distance([0, 0])}, TypeError);
assert.throws(function() {math.distance([9, 4, 3.6])}, TypeError);
assert.throws(function() {math.distance([[1, 2, 4],math.matrix([1, 2]),[8, 1, 3]])}, TypeError);
assert.throws(function() {math.distance([-0.5, 4.3],[3.2, -4.654323, 3.3, 6.5, 3.4])}, TypeError);
});
it('should calculate pairwise distance between more than two 2D points accurately', function(){
assert.deepEqual(math.distance([[1,2],[1,2],[1,3]]), [0, 1, 1]);
assert.deepEqual(math.distance([[0,2],[-2,0],[0,2]]), [ 2.8284271247461903, 0, 2.8284271247461903 ]);
assert.deepEqual(math.distance([[1,2], [2,3], [2,4], [3,0]]),
[1.4142135623730951,2.23606797749979,2.8284271247461903,1,3.1622776601683795,4.123105625617661]);
});
it('should calculate pairwise distance between more than two 3D points accurately', function(){
assert.deepEqual(math.distance([[0,0,0],[1,0,0],[0,1,0],[0,0,1]]), [1,1,1,1.4142135623730951,1.4142135623730951,1.4142135623730951]);
assert.deepEqual(math.distance([[1,2,4],[1,2,6],[8,1,3]]), [2, 7.14142842854285, 7.681145747868608]);
assert.deepEqual(math.distance([[-41,52,24],[61,-28,60],[-38,11,53]]), [134.5362404707371, 50.309044912421065, 106.63489110042735]);
assert.deepEqual(math.distance([[3.1,5.2,4.5],[4.1,0.2,6.4],[-5.8,-4.1,3021]]), [5.441507144165116,3016.527465480797,3014.6193225679426]);
});
it('should calculate distance between a point and a line segment given by an equation in 2D accurately', function(){
assert.deepEqual(math.distance([0.1123, -0.242], [0.1316, -0.2421, 0.122135]), 0.7094821347343443);
assert.deepEqual(math.distance([10, 10], [8, 1, 3]), 11.535230316796387);
assert.deepEqual(math.distance([12.5, -0.5], [8.5, -1, 3.75]), 12.91095785619739);
assert.deepEqual(math.distance([-34510, -1032], [8996, -10599, 34653]), 21542.094604263482);
assert.deepEqual(math.distance({pointX: 10, pointY: 10}, {xCoeffLine: 8, yCoeffLine: 1, constant: 3}), 11.535230316796387);
});
it('should calculate distance between a point and a line segment given by two points in 2D accurately', function(){
assert.deepEqual(math.distance(math.matrix([10, 10]), math.matrix([2, 3]), math.matrix([-8, 0])), 8.759953130362847);
assert.deepEqual(math.distance([0.23, -0.1240], [-0.232, 13.292], [-0.34, 0.346]), 10.658908662088363);
assert.deepEqual(math.distance([-10, 0.54], [38, 12.8], [94.33, -239]), 10.012171799590002);
assert.deepEqual(math.distance({pointX: 1, pointY: 4}, {lineOnePtX: 6, lineOnePtY: 3}, {lineTwoPtX: 2, lineTwoPtY: 8}), 2.720549372624744);
});
it('should calculate distance between point and line segment(with parametric co-ordinates) in 3D accurately', function(){
assert.deepEqual(math.distance([2, 3, 1], [1, 1, 2, 5, 0, 1]), 2.3204774044612857);
assert.deepEqual(math.distance(math.matrix([1, -1, -1]), math.matrix([2, 2, 0, 1, 2, 2])), 1.414213562373095);
assert.deepEqual(math.distance([-341, 12, 84.34], [-3.2, 212, 1.240, -51241, 22.2, -4652]), 229.9871046141146);
assert.deepEqual(math.distance({pointX: 2, pointY: 3, pointZ: 1}, {x0: 1, y0: 1, z0: 2, a: 5, b: 0, c: 1}), 2.3204774044612857);
});
});

View File

@@ -0,0 +1,42 @@
var assert = require('assert');
var error = require('../../../lib/error/index');
var math = require('../../../index');
describe('intersect', function() {
it('should calculate the intersection point of two 2D lines', function() {
assert.deepEqual(math.intersect([0, 0], [10, 10], [10, 0], [0, 10]), [5, 5]);
assert.deepEqual(math.intersect(math.matrix([0, 0]), [10, 10], math.matrix([10, 0]), math.matrix([0, 10])), math.matrix([5, 5]));
assert.deepEqual(math.intersect(math.matrix([0, 0]), math.matrix([10, 10]), math.matrix([10, 0]), math.matrix([0, 10])), math.matrix([5, 5]));
assert.deepEqual(math.intersect([300, 90], [400, 97], [300, 130], [400, 125]), [633.3333333333334, 113.33333333333334]);
});
it('should calculate the intersection point of two 3D lines', function() {
assert.deepEqual(math.intersect([0, 0, 0], [10, 10, 0], [10, 0, 0], [0, 10, 0]), [5, 5, 0]);
assert.deepEqual(math.intersect(math.matrix([0, 0, 0]), [10, 10, 0], [10, 0, 0], math.matrix([0, 10, 0])), math.matrix([5, 5, 0]));
assert.deepEqual(math.intersect(math.matrix([0, 0, 0]), math.matrix([10, 10, 0]), math.matrix([10, 0, 0]), math.matrix([0, 10, 0])), math.matrix([5, 5, 0]));
});
it('should calculate the intersection point of a line and a plane', function() {
assert.deepEqual(math.intersect([1, 0, 1], [4, -2, 2], [1, 1, 1, 6]), [7, -4, 3]);
assert.deepEqual(math.intersect(math.matrix([1, 0, 1]), [4, -2, 2], math.matrix([1, 1, 1, 6])), math.matrix([7, -4, 3]));
assert.deepEqual(math.intersect(math.matrix([1, 0, 1]), math.matrix([4, -2, 2]), math.matrix([1, 1, 1, 6])), math.matrix([7, -4, 3]));
});
it('should return null if the points do not intersect', function() {
assert.deepEqual(math.intersect([0, 1, 0], [0, 0, 0], [1, 1, 0], [1, 0, 0]), null);
assert.deepEqual(math.intersect([0, 1], [0, 0], [1, 1], [1, 0]), null);
});
it('should throw an error when number of arguments are other than 3 or 4', function() {
assert.throws(function () {math.intersect([2, 0, 1], [1, 1, 1, 6])}, /TypeError: Too few arguments in function intersect/);
assert.throws(function () {math.intersect([2, 0, 1], [1, 1, 6], [2, 0, 1], [1, 1, 6], [0, 8, 1])}, /TypeError: Too many arguments in function intersect/);
});
it('should throw an error for incompatible parameter types', function() {
assert.throws(function () {math.intersect(2, 3, 6)}, /TypeError: Unexpected type of argument in function intersect/);
assert.throws(function () {math.intersect([2, 0, 1], [1, 1, 1], [5, 1, 10])}, /TypeError: Array with 4 numbers expected as third argument/);
assert.throws(function () {math.intersect([], [], [], [])}, /TypeError: Arrays with two or thee dimensional points expected/);
assert.throws(function () {math.intersect([2, 8, 9], 3, 6)}, /TypeError: Unexpected type of argument in function intersect/);
assert.throws(function () {math.intersect('a', 'b', 'c', 'd')}, /TypeError: Unexpected type of argument in function intersect/);
});
});

View File

@@ -0,0 +1,196 @@
// test and
var assert = require('assert'),
math = require('../../../index'),
bignumber = math.bignumber,
complex = math.complex,
matrix = math.matrix,
sparse = math.sparse,
unit = math.unit,
and = math.and;
describe('and', function () {
it('should and two numbers correctly', function () {
assert.strictEqual(and(1, 1), true);
assert.strictEqual(and(-1, 1), true);
assert.strictEqual(and(-1, -1), true);
assert.strictEqual(and(0, -1), false);
assert.strictEqual(and(1, 0), false);
assert.strictEqual(and(1, NaN), false);
assert.strictEqual(and(NaN, 1), false);
assert.strictEqual(and(1e10, 0.019209), true);
assert.strictEqual(and(-1.0e-100, 1.0e-100), true);
assert.strictEqual(and(Infinity, -Infinity), true);
});
it('should and two complex numbers', function () {
assert.strictEqual(and(complex(1, 1), complex(1, 1)), true);
assert.strictEqual(and(complex(0, 1), complex(1, 1)), true);
assert.strictEqual(and(complex(1, 0), complex(1, 1)), true);
assert.strictEqual(and(complex(1, 1), complex(0, 1)), true);
assert.strictEqual(and(complex(1, 1), complex(1, 0)), true);
assert.strictEqual(and(complex(1, 0), complex(1, 0)), true);
assert.strictEqual(and(complex(0, 1), complex(0, 1)), true);
assert.strictEqual(and(complex(0, 0), complex(1, 1)), false);
assert.strictEqual(and(complex(0, 0), complex(0, 1)), false);
assert.strictEqual(and(complex(0, 0), complex(1, 0)), false);
assert.strictEqual(and(complex(1, 1), complex(0, 0)), false);
assert.strictEqual(and(complex(0, 1), complex(0, 0)), false);
assert.strictEqual(and(complex(1, 0), complex(0, 0)), false);
assert.strictEqual(and(complex(), complex(1, 1)), false);
assert.strictEqual(and(complex(0), complex(1, 1)), false);
assert.strictEqual(and(complex(1), complex(1, 1)), true);
assert.strictEqual(and(complex(1, 1), complex()), false);
assert.strictEqual(and(complex(1, 1), complex(0)), false);
assert.strictEqual(and(complex(1, 1), complex(1)), true);
});
it('should and mixed numbers and complex numbers', function () {
assert.strictEqual(and(complex(1, 1), 1), true);
assert.strictEqual(and(complex(1, 1), 0), false);
assert.strictEqual(and(1, complex(1, 1)), true);
assert.strictEqual(and(0, complex(1, 1)), false);
assert.strictEqual(and(complex(0, 0), 1), false);
assert.strictEqual(and(1, complex(0, 0)), false);
});
it('should and two booleans', function () {
assert.strictEqual(and(true, true), true);
assert.strictEqual(and(true, false), false);
assert.strictEqual(and(false, true), false);
assert.strictEqual(and(false, false), false);
});
it('should and mixed numbers and booleans', function () {
assert.strictEqual(and(2, true), true);
assert.strictEqual(and(2, false), false);
assert.strictEqual(and(0, true), false);
assert.strictEqual(and(true, 2), true);
assert.strictEqual(and(false, 2), false);
});
it('should and mixed numbers and null', function () {
assert.strictEqual(and(2, null), false);
assert.strictEqual(and(null, 2), false);
});
it('should and bignumbers', function () {
assert.strictEqual(and(bignumber(1), bignumber(1)), true);
assert.strictEqual(and(bignumber(-1), bignumber(1)), true);
assert.strictEqual(and(bignumber(-1), bignumber(-1)), true);
assert.strictEqual(and(bignumber(0), bignumber(-1)), false);
assert.strictEqual(and(bignumber(1), bignumber(0)), false);
assert.strictEqual(and(bignumber(1), bignumber(NaN)), false);
assert.strictEqual(and(bignumber(NaN), bignumber(1)), false);
assert.strictEqual(and(bignumber('1e+10'), bignumber(0.19209)), true);
assert.strictEqual(and(bignumber('-1.0e-100'), bignumber('1.0e-100')), true);
assert.strictEqual(and(bignumber(Infinity), bignumber(-Infinity)), true);
});
it('should and mixed numbers and bignumbers', function () {
assert.strictEqual(and(bignumber(2), 3), true);
assert.strictEqual(and(2, bignumber(2)), true);
assert.strictEqual(and(0, bignumber(2)), false);
assert.strictEqual(and(2, bignumber(0)), false);
assert.strictEqual(and(bignumber(0), 2), false);
assert.strictEqual(and(bignumber(2), 0), false);
});
it('should and two units', function () {
assert.strictEqual(and(unit('100cm'), unit('10inch')), true);
assert.strictEqual(and(unit('100cm'), unit('0 inch')), false);
assert.strictEqual(and(unit('0cm'), unit('1m')), false);
assert.strictEqual(and(unit('m'), unit('1m')), false);
assert.strictEqual(and(unit('1dm'), unit('m')), false);
assert.strictEqual(and(unit('-100cm'), unit('-10inch')), true);
assert.strictEqual(and(unit(5, 'km'), unit(100, 'gram')), true);
assert.strictEqual(and(unit(5, 'km'), unit(0, 'gram')), false);
assert.strictEqual(and(unit(0, 'km'), unit(100, 'gram')), false);
assert.strictEqual(and(unit(bignumber(0), 'm'), unit(bignumber(0), 'm')), false);
assert.strictEqual(and(unit(bignumber(1), 'm'), unit(bignumber(0), 'm')), false);
assert.strictEqual(and(unit(bignumber(0), 'm'), unit(bignumber(1), 'm')), false);
assert.strictEqual(and(unit(bignumber(1), 'm'), unit(bignumber(1), 'm')), true);
});
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 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 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 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/);
});
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, 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)');
});
});

View File

@@ -0,0 +1,95 @@
// test not
var assert = require('assert');
var math = require('../../../index');
var bignumber = math.bignumber;
var complex = math.complex;
var matrix = math.matrix;
var unit = math.unit;
var not = math.not;
var FunctionNode = math.expression.node.FunctionNode;
var ConstantNode = math.expression.node.ConstantNode;
var SymbolNode = math.expression.node.SymbolNode;
describe('not', function () {
it('should not numbers correctly', function () {
assert.strictEqual(not(1), false);
assert.strictEqual(not(-1), false);
assert.strictEqual(not(1.23e+100), false);
assert.strictEqual(not(-1.0e-100), false);
assert.strictEqual(not(1.0e-100), false);
assert.strictEqual(not(Infinity), false);
assert.strictEqual(not(-Infinity), false);
assert.strictEqual(not(0), true);
assert.strictEqual(not(NaN), true);
});
it('should not complex numbers', function () {
assert.strictEqual(not(complex(1, 1)), false);
assert.strictEqual(not(complex(0, 1)), false);
assert.strictEqual(not(complex(1, 0)), false);
assert.strictEqual(not(complex(0, 0)), true);
assert.strictEqual(not(complex()), true);
assert.strictEqual(not(complex(0)), true);
assert.strictEqual(not(complex(1)), false);
});
it('should not booleans', function () {
assert.strictEqual(not(true), false);
assert.strictEqual(not(false), true);
});
it('should not null', function () {
assert.strictEqual(not(null), true);
});
it('should not bignumbers', function () {
assert.strictEqual(not(bignumber(1)), false);
assert.strictEqual(not(bignumber(-1)), false);
assert.strictEqual(not(bignumber(0)), true);
assert.strictEqual(not(bignumber(NaN)), true);
assert.strictEqual(not(bignumber('1e+10')), false);
assert.strictEqual(not(bignumber('-1.0e-100')), false);
assert.strictEqual(not(bignumber('1.0e-100')), false);
assert.strictEqual(not(bignumber(Infinity)), false);
assert.strictEqual(not(bignumber(-Infinity)), false);
});
it('should not units', function () {
assert.strictEqual(not(unit('100cm')), false);
assert.strictEqual(not(unit('0 inch')), true);
assert.strictEqual(not(unit('1m')), false);
assert.strictEqual(not(unit('m')), true);
assert.strictEqual(not(unit('-10inch')), false);
assert.strictEqual(not(unit(bignumber(1), 'm')), false);
assert.strictEqual(not(unit(bignumber(0), 'm')), true);
});
it('should not arrays', function () {
assert.deepEqual(not([0, 10]), [true, false]);
assert.deepEqual(not([]), []);
});
it('should not matrices', function () {
assert.deepEqual(not(matrix([0, 10])), matrix([true, false]));
assert.deepEqual(not(matrix([])), matrix([]));
});
it('should throw an error in case of invalid number of arguments', function () {
assert.throws(function () {not()}, /TypeError: Too few arguments/);
assert.throws(function () {not(1, 2)}, /TypeError: Too many arguments/);
});
it('should throw an error in case of invalid type if arguments', function () {
assert.throws(function () {not(new Date())}, /TypeError: Unexpected type of argument/);
assert.throws(function () {not({})}, /TypeError: Unexpected type of argument/);
});
it('should LaTeX not', function () {
var c = new ConstantNode(1);
var node = new FunctionNode(new SymbolNode('not'), [c]);
assert.equal(node.toTex(), '\\neg\\left(1\\right)');
});
});

View File

@@ -0,0 +1,227 @@
// test or
var assert = require('assert'),
math = require('../../../index'),
bignumber = math.bignumber,
complex = math.complex,
matrix = math.matrix,
sparse = math.sparse,
unit = math.unit,
or = math.or;
describe('or', function () {
it('should or two numbers correctly', function () {
assert.strictEqual(or(1, 1), true);
assert.strictEqual(or(-1, 1), true);
assert.strictEqual(or(-1, -1), true);
assert.strictEqual(or(0, -1), true);
assert.strictEqual(or(1, 0), true);
assert.strictEqual(or(1, NaN), true);
assert.strictEqual(or(NaN, 1), true);
assert.strictEqual(or(1e10, 0.019209), true);
assert.strictEqual(or(-1.0e-100, 1.0e-100), true);
assert.strictEqual(or(Infinity, -Infinity), true);
assert.strictEqual(or(NaN, NaN), false);
assert.strictEqual(or(NaN, 0), false);
assert.strictEqual(or(0, NaN), false);
assert.strictEqual(or(0, 0), false);
});
it('should or two complex numbers', function () {
assert.strictEqual(or(complex(1, 1), complex(1, 1)), true);
assert.strictEqual(or(complex(0, 1), complex(1, 1)), true);
assert.strictEqual(or(complex(1, 0), complex(1, 1)), true);
assert.strictEqual(or(complex(1, 1), complex(0, 1)), true);
assert.strictEqual(or(complex(1, 1), complex(1, 0)), true);
assert.strictEqual(or(complex(1, 0), complex(1, 0)), true);
assert.strictEqual(or(complex(0, 1), complex(0, 1)), true);
assert.strictEqual(or(complex(0, 0), complex(1, 1)), true);
assert.strictEqual(or(complex(0, 0), complex(0, 1)), true);
assert.strictEqual(or(complex(0, 0), complex(1, 0)), true);
assert.strictEqual(or(complex(1, 1), complex(0, 0)), true);
assert.strictEqual(or(complex(0, 1), complex(0, 0)), true);
assert.strictEqual(or(complex(1, 0), complex(0, 0)), true);
assert.strictEqual(or(complex(), complex(1, 1)), true);
assert.strictEqual(or(complex(0), complex(1, 1)), true);
assert.strictEqual(or(complex(1), complex(1, 1)), true);
assert.strictEqual(or(complex(1, 1), complex()), true);
assert.strictEqual(or(complex(1, 1), complex(0)), true);
assert.strictEqual(or(complex(1, 1), complex(1)), true);
assert.strictEqual(or(complex(0, 0), complex(0, 0)), false);
assert.strictEqual(or(complex(), complex()), false);
});
it('should or mixed numbers and complex numbers', function () {
assert.strictEqual(or(complex(1, 1), 1), true);
assert.strictEqual(or(complex(1, 1), 0), true);
assert.strictEqual(or(1, complex(1, 1)), true);
assert.strictEqual(or(0, complex(1, 1)), true);
assert.strictEqual(or(complex(0, 0), 1), true);
assert.strictEqual(or(1, complex(0, 0)), true);
assert.strictEqual(or(0, complex(0, 0)), false);
assert.strictEqual(or(complex(0, 0), 0), false);
});
it('should or two booleans', function () {
assert.strictEqual(or(true, true), true);
assert.strictEqual(or(true, false), true);
assert.strictEqual(or(false, true), true);
assert.strictEqual(or(false, false), false);
});
it('should or mixed numbers and booleans', function () {
assert.strictEqual(or(2, true), true);
assert.strictEqual(or(2, false), true);
assert.strictEqual(or(0, true), true);
assert.strictEqual(or(0, false), false);
assert.strictEqual(or(true, 2), true);
assert.strictEqual(or(false, 2), true);
assert.strictEqual(or(false, 0), false);
});
it('should or mixed numbers and null', function () {
assert.strictEqual(or(2, null), true);
assert.strictEqual(or(null, 2), true);
assert.strictEqual(or(null, null), false);
});
it('should or bignumbers', function () {
assert.strictEqual(or(bignumber(1), bignumber(1)), true);
assert.strictEqual(or(bignumber(-1), bignumber(1)), true);
assert.strictEqual(or(bignumber(-1), bignumber(-1)), true);
assert.strictEqual(or(bignumber(0), bignumber(-1)), true);
assert.strictEqual(or(bignumber(1), bignumber(0)), true);
assert.strictEqual(or(bignumber(1), bignumber(NaN)), true);
assert.strictEqual(or(bignumber(NaN), bignumber(1)), true);
assert.strictEqual(or(bignumber('1e+10'), bignumber(0.19209)), true);
assert.strictEqual(or(bignumber('-1.0e-100'), bignumber('1.0e-100')), true);
assert.strictEqual(or(bignumber(Infinity), bignumber(-Infinity)), true);
assert.strictEqual(or(bignumber(NaN), bignumber(NaN)), false);
assert.strictEqual(or(bignumber(NaN), bignumber(0)), false);
assert.strictEqual(or(bignumber(0), bignumber(NaN)), false);
assert.strictEqual(or(bignumber(0), bignumber(0)), false);
});
it('should or mixed numbers and bignumbers', function () {
assert.strictEqual(or(bignumber(2), 3), true);
assert.strictEqual(or(2, bignumber(2)), true);
assert.strictEqual(or(0, bignumber(2)), true);
assert.strictEqual(or(2, bignumber(0)), true);
assert.strictEqual(or(bignumber(0), 2), true);
assert.strictEqual(or(bignumber(0), 0), false);
assert.strictEqual(or(bignumber(2), 0), true);
assert.strictEqual(or(bignumber(0), 0), false);
});
it('should or two units', function () {
assert.strictEqual(or(unit('100cm'), unit('10inch')), true);
assert.strictEqual(or(unit('100cm'), unit('0 inch')), true);
assert.strictEqual(or(unit('0cm'), unit('1m')), true);
assert.strictEqual(or(unit('m'), unit('1m')), true);
assert.strictEqual(or(unit('1dm'), unit('m')), true);
assert.strictEqual(or(unit('dm'), unit('m')), false);
assert.strictEqual(or(unit('-100cm'), unit('-10inch')), true);
assert.strictEqual(or(unit(5, 'km'), unit(100, 'gram')), true);
assert.strictEqual(or(unit(5, 'km'), unit(0, 'gram')), true);
assert.strictEqual(or(unit(0, 'km'), unit(100, 'gram')), true);
assert.strictEqual(or(unit(0, 'km'), unit(0, 'gram')), false);
assert.strictEqual(or(unit(bignumber(0), 'm'), unit(bignumber(0), 'm')), false);
assert.strictEqual(or(unit(bignumber(1), 'm'), unit(bignumber(0), 'm')), true);
assert.strictEqual(or(unit(bignumber(0), 'm'), unit(bignumber(1), 'm')), true);
assert.strictEqual(or(unit(bignumber(1), 'm'), unit(bignumber(1), 'm')), true);
});
it('should or two arrays', function () {
assert.deepEqual(or([0, 1, 0, 12], [0, 0, 1, 22]), [false, true, true, true]);
assert.deepEqual(or([], []), []);
});
it('should or mixed numbers and arrays', function () {
assert.deepEqual(or(10, [0, 2]), [true, true]);
assert.deepEqual(or([0, 2], 10), [true, true]);
assert.deepEqual(or(0, [0, 2]), [false, true]);
assert.deepEqual(or([0, 2], 0), [false, true]);
});
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]]));
});
});
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/);
});
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, 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)');
});
});

View File

@@ -0,0 +1,216 @@
// test xor
var assert = require('assert'),
math = require('../../../index'),
bignumber = math.bignumber,
complex = math.complex,
matrix = math.matrix,
sparse = math.sparse,
unit = math.unit,
xor = math.xor;
describe('xor', function () {
it('should xor two numbers correctly', function () {
assert.strictEqual(xor(1, 1), false);
assert.strictEqual(xor(-1, 1), false);
assert.strictEqual(xor(-1, -1), false);
assert.strictEqual(xor(0, -1), true);
assert.strictEqual(xor(1, 0), true);
assert.strictEqual(xor(1, NaN), true);
assert.strictEqual(xor(NaN, 1), true);
assert.strictEqual(xor(1e10, 0.019209), false);
assert.strictEqual(xor(-1.0e-100, 1.0e-100), false);
assert.strictEqual(xor(Infinity, -Infinity), false);
assert.strictEqual(xor(NaN, NaN), false);
assert.strictEqual(xor(NaN, 0), false);
assert.strictEqual(xor(0, NaN), false);
assert.strictEqual(xor(0, 0), false);
});
it('should xor two complex numbers', function () {
assert.strictEqual(xor(complex(1, 1), complex(1, 1)), false);
assert.strictEqual(xor(complex(0, 1), complex(1, 1)), false);
assert.strictEqual(xor(complex(1, 0), complex(1, 1)), false);
assert.strictEqual(xor(complex(1, 1), complex(0, 1)), false);
assert.strictEqual(xor(complex(1, 1), complex(1, 0)), false);
assert.strictEqual(xor(complex(1, 0), complex(1, 0)), false);
assert.strictEqual(xor(complex(0, 1), complex(0, 1)), false);
assert.strictEqual(xor(complex(0, 0), complex(1, 1)), true);
assert.strictEqual(xor(complex(0, 0), complex(0, 1)), true);
assert.strictEqual(xor(complex(0, 0), complex(1, 0)), true);
assert.strictEqual(xor(complex(1, 1), complex(0, 0)), true);
assert.strictEqual(xor(complex(0, 1), complex(0, 0)), true);
assert.strictEqual(xor(complex(1, 0), complex(0, 0)), true);
assert.strictEqual(xor(complex(), complex(1, 1)), true);
assert.strictEqual(xor(complex(0), complex(1, 1)), true);
assert.strictEqual(xor(complex(1), complex(1, 1)), false);
assert.strictEqual(xor(complex(1, 1), complex()), true);
assert.strictEqual(xor(complex(1, 1), complex(0)), true);
assert.strictEqual(xor(complex(1, 1), complex(1)), false);
assert.strictEqual(xor(complex(0, 0), complex(0, 0)), false);
assert.strictEqual(xor(complex(), complex()), false);
});
it('should xor mixed numbers and complex numbers', function () {
assert.strictEqual(xor(complex(1, 1), 1), false);
assert.strictEqual(xor(complex(1, 1), 0), true);
assert.strictEqual(xor(1, complex(1, 1)), false);
assert.strictEqual(xor(0, complex(1, 1)), true);
assert.strictEqual(xor(complex(0, 0), 1), true);
assert.strictEqual(xor(1, complex(0, 0)), true);
assert.strictEqual(xor(0, complex(0, 0)), false);
assert.strictEqual(xor(complex(0, 0), 0), false);
});
it('should xor two booleans', function () {
assert.strictEqual(xor(true, true), false);
assert.strictEqual(xor(true, false), true);
assert.strictEqual(xor(false, true), true);
assert.strictEqual(xor(false, false), false);
});
it('should xor mixed numbers and booleans', function () {
assert.strictEqual(xor(2, true), false);
assert.strictEqual(xor(2, false), true);
assert.strictEqual(xor(0, true), true);
assert.strictEqual(xor(true, 2), false);
assert.strictEqual(xor(false, 2), true);
assert.strictEqual(xor(false, 0), false);
});
it('should xor mixed numbers and null', function () {
assert.strictEqual(xor(2, null), true);
assert.strictEqual(xor(null, 2), true);
});
it('should xor bignumbers', function () {
assert.strictEqual(xor(bignumber(1), bignumber(1)), false);
assert.strictEqual(xor(bignumber(-1), bignumber(1)), false);
assert.strictEqual(xor(bignumber(-1), bignumber(-1)), false);
assert.strictEqual(xor(bignumber(0), bignumber(-1)), true);
assert.strictEqual(xor(bignumber(1), bignumber(0)), true);
assert.strictEqual(xor(bignumber(1), bignumber(NaN)), true);
assert.strictEqual(xor(bignumber(NaN), bignumber(1)), true);
assert.strictEqual(xor(bignumber('1e+10'), bignumber(0.19209)), false);
assert.strictEqual(xor(bignumber('-1.0e-400'), bignumber('1.0e-400')), false);
assert.strictEqual(xor(bignumber(Infinity), bignumber(-Infinity)), false);
assert.strictEqual(xor(bignumber(NaN), bignumber(NaN)), false);
assert.strictEqual(xor(bignumber(NaN), bignumber(0)), false);
assert.strictEqual(xor(bignumber(0), bignumber(NaN)), false);
assert.strictEqual(xor(bignumber(0), bignumber(0)), false);
});
it('should xor mixed numbers and bignumbers', function () {
assert.strictEqual(xor(bignumber(2), 3), false);
assert.strictEqual(xor(2, bignumber(2)), false);
assert.strictEqual(xor(0, bignumber(2)), true);
assert.strictEqual(xor(2, bignumber(0)), true);
assert.strictEqual(xor(bignumber(0), 2), true);
assert.strictEqual(xor(bignumber(2), 0), true);
assert.strictEqual(xor(bignumber(0), 0), false);
});
it('should xor two units', function () {
assert.strictEqual(xor(unit('100cm'), unit('10inch')), false);
assert.strictEqual(xor(unit('100cm'), unit('0 inch')), true);
assert.strictEqual(xor(unit('0cm'), unit('1m')), true);
assert.strictEqual(xor(unit('m'), unit('1m')), true);
assert.strictEqual(xor(unit('1dm'), unit('m')), true);
assert.strictEqual(xor(unit('-100cm'), unit('-10inch')), false);
assert.strictEqual(xor(unit(5, 'km'), unit(100, 'gram')), false);
assert.strictEqual(xor(unit(5, 'km'), unit(0, 'gram')), true);
assert.strictEqual(xor(unit(0, 'km'), unit(100, 'gram')), true);
assert.strictEqual(xor(unit(0, 'km'), unit(0, 'gram')), false);
assert.strictEqual(xor(unit(bignumber(0), 'm'), unit(bignumber(0), 'm')), false);
assert.strictEqual(xor(unit(bignumber(1), 'm'), unit(bignumber(0), 'm')), true);
assert.strictEqual(xor(unit(bignumber(0), 'm'), unit(bignumber(1), 'm')), true);
assert.strictEqual(xor(unit(bignumber(1), 'm'), unit(bignumber(1), 'm')), false);
});
it('should xor two arrays', function () {
assert.deepEqual(xor([0, 1, 0, 12], [0, 0, 1, 22]), [false, true, true, false]);
assert.deepEqual(xor([], []), []);
});
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]]));
});
});
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]]));
});
});
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 () {
assert.throws(function () {xor(1)}, /TypeError: Too few arguments/);
assert.throws(function () {xor(1, 2, 3)}, /TypeError: Too many arguments/);
});
it('should throw an error in case of invalid type of arguments', function () {
assert.throws(function () {xor(new Date(), true)}, /TypeError: Unexpected type of argument/);
assert.throws(function () {xor(true, new Date())}, /TypeError: Unexpected type of argument/);
assert.throws(function () {xor(true, undefined)}, /TypeError: Unexpected type of argument/);
assert.throws(function () {xor(undefined, true)}, /TypeError: Unexpected type of argument/);
});
it('should LaTeX xor', function () {
var expression = math.parse('xor(1,2)');
assert.equal(expression.toTex(), '\\left(1\\veebar2\\right)');
});
});

View File

@@ -0,0 +1,114 @@
var assert = require('assert'),
error = require('../../../lib/error/index'),
math = require('../../../index'),
bignumber = math.bignumber;
describe('concat', function() {
var a = [[1,2],[3,4]];
var b = [[5,6],[7,8]];
var c = [[9,10],[11,12]];
var d = [
[ [1,2], [3,4] ],
[ [5,6], [7,8] ]
];
var e = [
[ [9,10], [11,12] ],
[ [13,14], [15,16] ]
];
it('should concatenate compatible matrices on the last dimension by default', function() {
assert.deepEqual(math.concat([1,2,3], [4, 5]), [1,2,3,4,5]);
assert.deepEqual(math.concat(
[bignumber(1),bignumber(2),bignumber(3)],
[bignumber(4)]),
[bignumber(1),bignumber(2),bignumber(3),bignumber(4)]);
assert.deepEqual(math.concat([[1],[2],[3]], [[4]], 0), [[1],[2],[3],[4]]);
assert.deepEqual(math.concat([[],[]], [[1,2],[3,4]]), [[1,2],[3,4]]);
assert.deepEqual(math.concat(math.matrix(a), math.matrix(b)), math.matrix([
[1,2,5,6],
[3,4,7,8]
]));
assert.deepEqual(math.concat(a, b, c), [
[1,2,5,6,9,10],
[3,4,7,8,11,12]
]);
assert.deepEqual(math.concat(d,e), [
[ [1,2,9,10], [3,4,11,12] ],
[ [5,6,13,14], [7,8,15,16] ]
]);
});
it('should concatenate compatible matrices on the given dimension', function() {
assert.deepEqual(math.concat([[1]], [[2]], 1), [[1,2]]);
assert.deepEqual(math.concat([[1]], [[2]], 0), [[1],[2]]);
assert.deepEqual(math.concat([[1]], [[2]], 0), [[1],[2]]);
assert.deepEqual(math.concat(a, b, 0), [
[1,2],
[3,4],
[5,6],
[7,8]
]);
assert.deepEqual(math.concat(a, b, c, 0), [
[1,2],
[3,4],
[5,6],
[7,8],
[9,10],
[11,12]
]);
assert.deepEqual(math.concat(d,e,0), [
[ [1,2], [3,4] ],
[ [5,6], [7,8] ],
[ [9,10], [11,12] ],
[ [13,14], [15,16] ]
]);
assert.deepEqual(math.concat(d,e,1), [
[ [1,2], [3,4], [9,10], [11,12] ],
[ [5,6], [7,8], [13,14], [15,16] ]
]);
assert.deepEqual(math.concat(d,e, bignumber(1)), [
[ [1,2], [3,4], [9,10], [11,12] ],
[ [5,6], [7,8], [13,14], [15,16] ]
]);
});
it('should concatenate strings', function() {
assert.strictEqual(math.concat('a', 'b'), 'ab');
assert.strictEqual(math.concat('a', 'b', 'c'), 'abc');
});
it('should throw an error in case of invalid requested dimension number', function() {
assert.throws(function () {math.concat([1, 2], [3,4], 2.3)}, /Integer number expected for dimension/);
assert.throws(function () {math.concat([1, 2], [3,4], 1)}, /Index out of range \(1 > 0\)/);
});
it('should throw an error in case dimension mismatch', function() {
assert.throws(function () {math.concat([1, 2], [[1,2], [3,4]])}, RangeError);
assert.throws(function () {math.concat([[1, 2]], [[1,2], [3,4]])}, /Dimension mismatch/);
});
it('should throw an error in case of invalid type of argument', function() {
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() {
assert.throws(function () {math.concat(2)}, /At least one matrix expected/);
});
it('should LaTeX concat', function () {
var expression = math.parse('concat([1],[2])');
assert.equal(expression.toTex(), '\\mathrm{concat}\\left(\\begin{bmatrix}1\\\\\\end{bmatrix},\\begin{bmatrix}2\\\\\\end{bmatrix}\\right)');
});
});

View File

@@ -0,0 +1,52 @@
var assert = require('assert');
var error = require('../../../lib/error/index');
var math = require('../../../index');
describe('cross', function() {
it('should calculate cross product for two arrays', function() {
assert.deepEqual(math.cross([1, 1, 0], [0, 1, 1]), [1, -1, 1]);
assert.deepEqual(math.cross([3, -3, 1], [4, 9, 2]), [-15, -2, 39]);
assert.deepEqual(math.cross([2, 3, 4], [5, 6, 7]), [-3, 6, -3]);
});
it('should calculate cross product for two matrices', function() {
assert.deepEqual(math.cross(math.matrix([1, 1, 0]), math.matrix([0, 1, 1])),
math.matrix([1, -1, 1]));
});
it('should calculate cross product for mixed arrays and matrices', function() {
assert.deepEqual(math.cross([1, 1, 0], math.matrix([0, 1, 1])),
math.matrix([1, -1, 1]));
assert.deepEqual(math.cross(math.matrix([1, 1, 0]), [0, 1, 1]),
math.matrix([1, -1, 1]));
});
it('should calculate cross product for n-d arrays and matrices', function () {
assert.deepEqual(math.cross([[1, 2, 3]], [[4, 5, 6]]), [[-3, 6, -3]]);
assert.deepEqual(math.cross([[1], [2], [3]], [4, 5, 6]), [[-3, 6, -3]]);
assert.deepEqual(math.cross([[[[1, 2, 3]]]], [[4, 5, 6]]), [[-3, 6, -3]]);
});
it('should throw an error for unsupported types of arguments', function() {
assert.throws(function () {math.cross([2, 4, 1], 2)}, TypeError);
});
it('should throw an error for multi dimensional matrix input', function() {
assert.throws(function () {math.cross([[1,2],[3,4]], [[1,2],[3,4]])}, /Vectors with length 3 expected/);
});
it('should throw an error in case of vectors with unequal length', function() {
assert.throws(function () {math.cross([2, 3], [1,2,3])}, /Vectors with length 3 expected/);
});
it('should throw an error in case of empty vectors', function() {
assert.throws(function () {math.cross([], [])}, /Vectors with length 3 expected/);
});
it('should LaTeX cross', function () {
var expression = math.parse('cross([1],[2])');
assert.equal(expression.toTex(), '\\left(\\begin{bmatrix}1\\\\\\end{bmatrix}\\right)\\times\\left(\\begin{bmatrix}2\\\\\\end{bmatrix}\\right)');
});
});

Some files were not shown because too many files have changed in this diff Show More