diff --git a/Jakefile.js b/Jakefile.js index 8f9753048..188a53327 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -114,6 +114,45 @@ task('test', ['concat'], function () { console.log('Executed ' + files.length + ' test files successfully'); }); +/** + * build task + */ +desc('Build the library using browserify'); +task('dist', {async: true}, function () { + var browserify = require('browserify'); + var b = browserify(); + // TODO: make directory dist + var dist = './dist/math.js'; + var distMin = './dist/math.min.js'; + b.add('./src/index.js'); + b.bundle({ + standalone: 'math' + }, function (err, code) { + if(err) { + throw err; + } + + // add header and shim + var lib = util.read('./src/header.js') + code + util.read('./src/shim.js'); + + // write bundled file + util.write(dist, lib); + + // update version number and stuff in the javascript files + updateVersion(dist); + + // minify + var result = util.minify({ + src: dist, + dest: distMin, + header: util.read(HEADER) + }); + updateVersion(distMin); + + complete(); + }); +}); + /** * Update version and date patterns in given file. * Patterns '@@date' and '@@version' will be replaced with current date and diff --git a/dist/math.js b/dist/math.js index 077bc40af..e69de29bb 100644 --- a/dist/math.js +++ b/dist/math.js @@ -1,12037 +0,0 @@ -/** - * math.js - * https://github.com/josdejong/mathjs - * - * Math.js is an extensive math library for JavaScript and Node.js, - * It features real and complex numbers, units, matrices, a large set of - * mathematical functions, and a flexible expression parser. - * - * @version 0.11.2-SNAPSHOT - * @date 2013-08-04 - * - * @license - * Copyright (C) 2013 Jos de Jong - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -(function() { - -// TODO: put "use strict"; here (but right now webstorms inspector starts -// complaining on this issue: http://youtrack.jetbrains.com/issue/WEB-7485) - -/** - * Define namespace - */ -var math = { - type: {}, - expr: { - node: { - handlers: {} - } - }, - docs: {}, - options: { - precision: 5 // number of digits in formatted output - } -}; - -// utility methods for strings, objects, and arrays -var util = (function () { - var util = {}; - - /** - * Convert a number to a formatted string representation. - * @param {Number} value The value to be formatted - * @param {Number} [precision] number of digits in formatted output - * @return {String} formattedValue The formatted value - */ - util.formatNumber = function formatNumber(value, precision) { - if (value === Infinity) { - return 'Infinity'; - } - else if (value === -Infinity) { - return '-Infinity'; - } - else if (isNaN(value)) { - return 'NaN'; - } - - // TODO: what is a nice limit for non-scientific values? - var abs = Math.abs(value); - if ( (abs > 0.001 && abs < 100000) || abs == 0.0 ) { - // round the value to a limited number of precision - return util.toPrecision(value, precision); - } - else { - // scientific notation - var exp = Math.round(Math.log(abs) / Math.LN10); - var v = value / (Math.pow(10.0, exp)); - return util.toPrecision(v, precision) + 'e' + exp; - } - }; - - /** - * Round a value to a maximum number of precision. Trailing zeros will be - * removed. - * @param {Number} value - * @param {Number} [precision] Number of digits in formatted output - * @returns {string} str - */ - util.toPrecision = function toPrecision (value, precision) { - return value.toPrecision(precision).replace(_trailingZeros, function (a, b, c) { - return a.substring(0, a.length - (b.length ? 0 : 1) - c.length); - }); - }; - - /** @private */ - var _trailingZeros = /\.(\d*?)(0+)$/g; - - /** - * Recursively format an n-dimensional matrix - * Example output: "[[1, 2], [3, 4]]" - * @param {Array} array - * @returns {String} str - */ - util.formatArray = function formatArray (array) { - if (Array.isArray(array)) { - var str = '['; - var len = array.length; - for (var i = 0; i < len; i++) { - if (i != 0) { - str += ', '; - } - str += util.formatArray(array[i]); - } - str += ']'; - return str; - } - else { - return math.format(array); - } - }; - - /** - * Recursively format an n-dimensional array, output looks like - * "[1, 2, 3]" - * @param {Array} array - * @returns {string} str - */ - util.formatArray2d = function formatArray2d (array) { - var str = '['; - var s = util.size(array); - - if (s.length != 2) { - throw new RangeError('Array must be two dimensional (size: ' + - util.formatArray(s) + ')'); - } - - var rows = s[0]; - var cols = s[1]; - for (var r = 0; r < rows; r++) { - if (r != 0) { - str += '; '; - } - - var row = array[r]; - for (var c = 0; c < cols; c++) { - if (c != 0) { - str += ', '; - } - var cell = row[c]; - if (cell != undefined) { - str += math.format(cell); - } - } - } - str += ']'; - - return str; - }; - - /** - * Convert function arguments to an array. Arguments can have the following - * signature: - * fn() - * fn(n) - * fn(m, n, p, ...) - * fn([m, n, p, ...]) - * @param {...Number | Array | Matrix} args - * @returns {Array} array - */ - util.argsToArray = function argsToArray(args) { - var array; - if (args.length == 0) { - // fn() - array = []; - } - else if (args.length == 1) { - // fn(n) - // fn([m, n, p, ...]) - array = args[0]; - if (array instanceof Matrix) { - array = array.toVector(); - } - if (array instanceof Range) { - array = array.valueOf(); - } - if (!Array.isArray(array)) { - array = [array]; - } - } - else { - // fn(m, n, p, ...) - array = []; - for (var i = 0; i < args.length; i++) { - array[i] = args[i]; - } - } - return array; - }; - - /** - * Check if a text ends with a certain string. - * @param {String} text - * @param {String} search - */ - util.endsWith = function endsWith(text, search) { - var start = text.length - search.length; - var end = text.length; - return (text.substring(start, end) === search); - }; - - /** - * Extend object a with the properties of object b - * @param {Object} a - * @param {Object} b - * @return {Object} a - */ - util.extend = function extend (a, b) { - for (var prop in b) { - if (b.hasOwnProperty(prop)) { - a[prop] = b[prop]; - } - } - return a; - }; - - /** - * Deep extend an object a with the properties of object b - * @param {Object} a - * @param {Object} b - * @returns {Object} - */ - util.deepExtend = function deepExtend (a, b) { - for (var prop in b) { - if (b.hasOwnProperty(prop)) { - if (b[prop] && b[prop].constructor === Object) { - if (a[prop] === undefined) { - a[prop] = {}; - } - if (a[prop].constructor === Object) { - deepExtend(a[prop], b[prop]); - } - else { - a[prop] = b[prop]; - } - } else { - a[prop] = b[prop]; - } - } - } - return a; - }; - - /** - * Create a semi UUID - * b: http://stackoverflow.com/a/105074/1262753 - * @return {String} uuid - */ - util.randomUUID = function randomUUID() { - var S4 = function () { - return Math.floor( - Math.random() * 0x10000 /* 65536 */ - ).toString(16); - }; - - return ( - S4() + S4() + '-' + - S4() + '-' + - S4() + '-' + - S4() + '-' + - S4() + S4() + S4() - ); - }; - - // TODO: write the map, deepMap, map2, and deepMap2 functions in a more concise way - - /** - * Execute function fn element wise for each element in array. - * Returns an array with the results - * @param {Array | Matrix | Range} array - * @param {function} fn - * @return {Array | Matrix} res - */ - util.map = function map(array, fn) { - if (Array.isArray(array) || array instanceof Matrix || array instanceof Range) { - return array.map(function (x) { - return fn(x); - }); - } - else { - throw new TypeError('Array expected'); - } - }; - - /** - * Execute function fn element wise for each element in array and any nested - * array - * Returns an array with the results - * @param {Array | Matrix | Range} array - * @param {function} fn - * @return {Array | Matrix} res - */ - util.deepMap = function map(array, fn) { - if (Array.isArray(array) || array instanceof Matrix || array instanceof Range) { - return array.map(function (x) { - return map(x, fn); - }); - } - else { - return fn(array); - } - }; - - /** - * Execute function fn element wise for each entry in two given arrays, or - * for a (scalar) object and array pair. Returns an array with the results - * @param {Array | Matrix | Range | Object} array1 - * @param {Array | Matrix | Range | Object} array2 - * @param {function} fn - * @return {Array | Matrix} res - */ - util.map2 = function map2(array1, array2, fn) { - var res, len, i; - - // handle Matrix - if (array1 instanceof Matrix || array2 instanceof Matrix) { - return new Matrix(util.map2(array1.valueOf(), array2.valueOf(), fn)); - } - - // handle Range - if (array1 instanceof Range || array2 instanceof Range) { - // TODO: util.map2 does not utilize Range.map - return util.map2(array1.valueOf(), array2.valueOf(), fn); - } - - if (Array.isArray(array1)) { - if (Array.isArray(array2)) { - // fn(array, array) - if (array1.length != array2.length) { - throw new RangeError('Dimension mismatch ' + - '(' + array1.length + ' != ' + array2.length + ')'); - } - - res = []; - len = array1.length; - for (i = 0; i < len; i++) { - res[i] = fn(array1[i], array2[i]); - } - } - else { - // fn(array, object) - res = []; - len = array1.length; - for (i = 0; i < len; i++) { - res[i] = fn(array1[i], array2); - } - } - } - else { - if (Array.isArray(array2)) { - // fn(object, array) - res = []; - len = array2.length; - for (i = 0; i < len; i++) { - res[i] = fn(array1, array2[i]); - } - } - else { - // fn(object, object) - res = fn(array1, array2); - } - } - - return res; - }; - - /** - * Execute function fn element wise for each entry in two given arrays, - * and for any nested array. Objects can also be scalar objects. - * Returns an array with the results. - * @param {Array | Matrix | Range | Object} array1 - * @param {Array | Matrix | Range | Object} array2 - * @param {function} fn - * @return {Array | Matrix} res - */ - util.deepMap2 = function map2(array1, array2, fn) { - var res, len, i; - - // handle Matrix - if (array1 instanceof Matrix || array2 instanceof Matrix) { - return new Matrix(map2(array1.valueOf(), array2.valueOf(), fn)); - } - - // handle Range - if (array1 instanceof Range || array2 instanceof Range) { - // TODO: util.deepMap2 does not utilize Range.map - return map2(array1.valueOf(), array2.valueOf(), fn); - } - - if (Array.isArray(array1)) { - if (Array.isArray(array2)) { - // fn(array, array) - if (array1.length != array2.length) { - throw new RangeError('Dimension mismatch ' + - '(' + array1.length + ' != ' + array2.length + ')'); - } - - res = []; - len = array1.length; - for (i = 0; i < len; i++) { - res[i] = map2(array1[i], array2[i], fn); - } - } - else { - // fn(array, object) - res = []; - len = array1.length; - for (i = 0; i < len; i++) { - res[i] = map2(array1[i], array2, fn); - } - } - } - else { - if (Array.isArray(array2)) { - // fn(object, array) - res = []; - len = array2.length; - for (i = 0; i < len; i++) { - res[i] = map2(array1, array2[i], fn); - } - } - else { - // fn(object, object) - res = fn(array1, array2); - } - } - - return res; - }; - - /** - * Creates a new object with the results of calling a provided function on - * every prop in the object. - * @param {Object} object The object. - * @param {function} callback Mapping function - * @return {Object | Array} mappedObject - */ - util.mapObject = function mapObject (object, callback) { - var m = {}; - for (var key in object) { - if (object.hasOwnProperty(key)) { - m[key] = callback(object[key]); - } - } - return m; - }; - - /** - * Deep test equality of all fields in two pairs of arrays or objects. - * @param {Array | Object} a - * @param {Array | Object} b - * @returns {boolean} - */ - util.deepEqual = function deepEqual (a, b) { - var prop, i, len; - if (Array.isArray(a)) { - if (!Array.isArray(b)) { - return false; - } - - for (i = 0, len = a.length; i < len; i++) { - if (!util.deepEqual(a[i], b[i])) { - return false; - } - } - return true; - } - else if (a instanceof Object) { - if (Array.isArray(b) || !(b instanceof Object)) { - return false; - } - - for (prop in a) { - if (a.hasOwnProperty(prop)) { - if (!util.deepEqual(a[prop], b[prop])) { - return false; - } - } - } - for (prop in b) { - if (b.hasOwnProperty(prop)) { - if (!util.deepEqual(a[prop], b[prop])) { - return false; - } - } - } - return true; - } - else { - return (a.valueOf() == b.valueOf()); - } - }; - - /** - * Recursively calculate the size of a multi dimensional array. - * @param {Array} x - * @Return {Number[]} size - * @throws RangeError - */ - function _size(x) { - if (Array.isArray(x)) { - var sizeX = x.length; - if (sizeX) { - var size0 = _size(x[0]); - if (size0[0] == 0) { - return [0].concat(size0); - } - else { - return [sizeX].concat(size0); - } - } - else { - return [sizeX]; - } - } - else { - return []; - } - } - - /** - * Calculate the size of a multi dimensional array. - * All elements in the array are checked for matching dimensions using the - * method validate - * @param {Array} x - * @Return {Number[]} size - * @throws RangeError - */ - util.size = function size (x) { - // calculate the size - var s = _size(x); - - // verify the size - util.validate(x, s); - - return s; - }; - - /** - * Recursively validate whether each element in a multi dimensional array - * has a size corresponding to the provided size array. - * @param {Array} array Array to be validated - * @param {Number[]} size Array with the size of each dimension - * @param {Number} dim Current dimension - * @throws RangeError - */ - function _validate(array, size, dim) { - var i; - var len = array.length; - - if (len != size[dim]) { - throw new RangeError('Dimension mismatch (' + len + ' != ' + size[dim] + ')'); - } - - if (dim < size.length - 1) { - // recursively validate each child array - var dimNext = dim + 1; - for (i = 0; i < len; i++) { - var child = array[i]; - if (!Array.isArray(child)) { - throw new RangeError('Dimension mismatch ' + - '(' + (size.length - 1) + ' < ' + size.length + ')'); - } - _validate(array[i], size, dimNext); - } - } - else { - // last dimension. none of the childs may be an array - for (i = 0; i < len; i++) { - if (Array.isArray(array[i])) { - throw new RangeError('Dimension mismatch ' + - '(' + (size.length + 1) + ' > ' + size.length + ')'); - } - } - } - } - - /** - * Recursively validate whether each array in a multi dimensional array - * is empty (zero size) and has the correct number dimensions. - * @param {Array} array Array to be validated - * @param {Number[]} size Array with the size of each dimension - * @param {Number} dim Current dimension - * @throws RangeError - */ - function _validateEmpty(array, size, dim) { - if (dim < size.length - 1) { - var child = array[0]; - if (array.length != 1 || !Array.isArray(child)) { - throw new RangeError('Dimension mismatch ' + '(' + array.length + ' > 0)'); - } - - _validateEmpty(child, size, dim + 1); - } - else { - // last dimension. test if empty - if (array.length) { - throw new RangeError('Dimension mismatch ' + '(' + array.length + ' > 0)'); - } - } - } - - /** - * Validate whether each element in a multi dimensional array has - * a size corresponding to the provided size array. - * @param {Array} array Array to be validated - * @param {Number[]} size Array with the size of each dimension - * @throws RangeError - */ - util.validate = function validate(array, size) { - var isScalar = (size.length == 0); - if (isScalar) { - // scalar - if (Array.isArray(array)) { - throw new RangeError('Dimension mismatch (' + array.length + ' != 0)'); - } - return; - } - - var hasZeros = (size.indexOf(0) != -1); - if (hasZeros) { - // array where all dimensions are zero - size.forEach(function (value) { - if (value != 0) { - throw new RangeError('Invalid size, all dimensions must be ' + - 'either zero or non-zero (size: ' + util.formatArray(size) + ')'); - } - }); - - _validateEmpty(array, size, 0); - } - else { - _validate(array, size, 0); - } - }; - - /** - * Test whether index is an integer number with index >= 0 and index < length - * @param {*} index Zero-based index - * @param {Number} [length] Length of the array - */ - util.validateIndex = function validateIndex (index, length) { - if (!isNumber(index) || !isInteger(index)) { - throw new TypeError('Index must be an integer (value: ' + index + ')'); - } - if (index < 0) { - throw new RangeError('Index out of range (' + index + ' < 0)'); - } - if (length !== undefined && index >= length) { - throw new RangeError('Index out of range (' + index + ' >= ' + length + ')'); - } - }; - - /** - * Recursively resize a multi dimensional array - * @param {Array} array Array to be resized - * @param {Number[]} size Array with the size of each dimension - * @param {Number} dim Current dimension - * @param {*} [defaultValue] Value to be filled in in new entries, - * 0 by default. - * @private - */ - function _resize (array, size, dim, defaultValue) { - if (!Array.isArray(array)) { - throw new TypeError('Array expected'); - } - - var len = array.length, - newLen = size[dim]; - - if (len != newLen) { - if(newLen > array.length) { - // enlarge - for (var i = array.length; i < newLen; i++) { - array[i] = defaultValue ? math.clone(defaultValue) : 0; - } - } - else { - // shrink - array.length = size[dim]; - } - len = array.length; - } - - if (dim < size.length - 1) { - // recursively validate each child array - var dimNext = dim + 1; - for (i = 0; i < len; i++) { - child = array[i]; - if (!Array.isArray(child)) { - child = [child]; - array[i] = child; - } - _resize(child, size, dimNext, defaultValue); - } - } - else { - // last dimension - for (i = 0; i < len; i++) { - var child = array[i]; - while (Array.isArray(child)) { - child = child[0]; - } - array[i] = child; - } - } - } - - /** - * Resize a multi dimensional array - * @param {Array} array Array to be resized - * @param {Number[]} size Array with the size of each dimension - * @param {*} [defaultValue] Value to be filled in in new entries, - * 0 by default - */ - util.resize = function resize(array, size, defaultValue) { - // TODO: what to do with scalars, when size=[] ? - - // check the type of size - if (!Array.isArray(size)) { - throw new TypeError('Size must be an array (size is ' + math['typeof'](size) + ')'); - } - - // check whether size contains positive integers - size.forEach(function (value) { - if (!isNumber(value) || !isInteger(value) || value < 0) { - throw new TypeError('Invalid size, must contain positive integers ' + - '(size: ' + util.formatArray(size) + ')'); - } - }); - - var hasZeros = (size.indexOf(0) != -1); - if (hasZeros) { - // array where all dimensions are zero - size.forEach(function (value) { - if (value != 0) { - throw new RangeError('Invalid size, all dimensions must be ' + - 'either zero or non-zero (size: ' + util.formatArray(size) + ')'); - } - }); - } - - // recursively resize - _resize(array, size, 0, defaultValue); - }; - - return util; -})(); - -/** - * Utility functions for Booleans - */ - - -/** - * Test whether value is a Boolean - * @param {*} value - * @return {Boolean} isBoolean - */ -function isBoolean(value) { - return (value instanceof Boolean) || (typeof value == 'boolean'); -} - -/** - * @constructor Complex - * - * A complex value can be constructed in the following ways: - * var a = new Complex(); - * var b = new Complex(re, im); - * var c = Complex.parse(str); - * - * Example usage: - * var a = new Complex(3, -4); // 3 - 4i - * a.re = 5; // a = 5 - 4i - * var i = a.im; // -4; - * var b = Complex.parse('2 + 6i'); // 2 + 6i - * var c = new Complex(); // 0 + 0i - * var d = math.add(a, b); // 5 + 2i - * - * @param {Number} re The real part of the complex value - * @param {Number} [im] The imaginary part of the complex value - */ -function Complex(re, im) { - if (!(this instanceof Complex)) { - throw new SyntaxError( - 'Complex constructor must be called with the new operator'); - } - - switch (arguments.length) { - case 0: - this.re = 0; - this.im = 0; - break; - - case 2: - if (!isNumber(re) || !isNumber(im)) { - throw new TypeError( - 'Two numbers expected in Complex constructor'); - } - this.re = re; - this.im = im; - break; - - default: - if (arguments.length != 0 && arguments.length != 2) { - throw new SyntaxError( - 'Two or zero arguments expected in Complex constructor'); - } - break; - } -} - -math.type.Complex = Complex; - -// Complex parser methods in a closure -(function () { - var text, index, c; - - function skipWhitespace() { - while (c == ' ' || c == '\t') { - next(); - } - } - - function isDigitDot (c) { - return ((c >= '0' && c <= '9') || c == '.'); - } - - function isDigit (c) { - return ((c >= '0' && c <= '9')); - } - - function next() { - index++; - c = text.charAt(index); - } - - function revert(oldIndex) { - index = oldIndex; - c = text.charAt(index); - } - - function parseNumber () { - var number = ''; - var oldIndex; - oldIndex = index; - - if (c == '+') { - next(); - } - else if (c == '-') { - number += c; - next(); - } - - if (!isDigitDot(c)) { - // a + or - must be followed by a digit - revert(oldIndex); - return null; - } - - // get number, can have a single dot - if (c == '.') { - number += c; - next(); - if (!isDigit(c)) { - // this is no legal number, it is just a dot - revert(oldIndex); - return null; - } - } - else { - while (isDigit(c)) { - number += c; - next(); - } - if (c == '.') { - number += c; - next(); - } - } - while (isDigit(c)) { - number += c; - next(); - } - - // check for scientific notation like "2.3e-4" or "1.23e50" - if (c == 'E' || c == 'e') { - number += c; - next(); - - if (c == '+' || c == '-') { - number += c; - next(); - } - - // Scientific notation MUST be followed by an exponent - if (!isDigit(c)) { - // this is no legal number, exponent is missing. - revert(oldIndex); - return null; - } - - while (isDigit(c)) { - number += c; - next(); - } - } - - return number; - } - - function parseComplex () { - // check for 'i', '-i', '+i' - var cnext = text.charAt(index + 1); - if (c == 'I' || c == 'i') { - next(); - return '1'; - } - else if ((c == '+' || c == '-') && (cnext == 'I' || cnext == 'i')) { - var number = (c == '+') ? '1' : '-1'; - next(); - next(); - return number; - } - - return null; - } - - /** - * Create a complex number from a provided real and imaginary number. - * When the imaginary part is zero, a real number is returned instead of - * a complex number. For example: - * Complex.create(2, 3); // returns a Complex(2, 3) - * Complex.create(2, 0); // returns a Number 2 - * - * @param {Number} re - * @param {Number} im - * @return {Complex | Number} value - */ - Complex.create = function (re, im) { - if (im == 0) { - return re; - } - else { - return new Complex(re, im); - } - }; - - /** - * Parse a complex number from a string. For example Complex.parse("2 + 3i") - * will return a Complex value where re = 2, im = 3. - * Returns null if provided string does not contain a valid complex number. - * @param {String} str - * @returns {Complex | null} complex - */ - Complex.parse = function parse(str) { - text = str; - index = -1; - c = ''; - - if (!isString(text)) { - return null; - } - - next(); - skipWhitespace(); - var first = parseNumber(); - if (first) { - if (c == 'I' || c == 'i') { - // pure imaginary number - next(); - skipWhitespace(); - if (c) { - // garbage at the end. not good. - return null; - } - - return new Complex(0, Number(first)); - } - else { - // complex and real part - skipWhitespace(); - var separator = c; - if (separator != '+' && separator != '-') { - // pure real number - skipWhitespace(); - if (c) { - // garbage at the end. not good. - return null; - } - - return new Complex(Number(first), 0); - } - else { - // complex and real part - next(); - skipWhitespace(); - var second = parseNumber(); - if (second) { - if (c != 'I' && c != 'i') { - // 'i' missing at the end of the complex number - return null; - } - next(); - } - else { - second = parseComplex(); - if (!second) { - // imaginary number missing after separator - return null; - } - } - - if (separator == '-') { - if (second[0] == '-') { - second = '+' + second.substring(1); - } - else { - second = '-' + second; - } - } - - next(); - skipWhitespace(); - if (c) { - // garbage at the end. not good. - return null; - } - - return new Complex(Number(first), Number(second)); - } - } - } - else { - // check for 'i', '-i', '+i' - first = parseComplex(); - if (first) { - skipWhitespace(); - if (c) { - // garbage at the end. not good. - return null; - } - - return new Complex(0, Number(first)); - } - } - - return null; - }; - -})(); - -/** - * Test whether value is a Complex value - * @param {*} value - * @return {Boolean} isComplex - */ -function isComplex(value) { - return (value instanceof Complex); -} - -/** - * Create a copy of the complex value - * @return {Complex} clone - */ -Complex.prototype.clone = function () { - return new Complex(this.re, this.im); -}; - -/** - * Get string representation of the Complex value - * @return {String} str - */ -Complex.prototype.toString = function () { - var str = ''; - var strRe = util.formatNumber(this.re, math.options.precision); - var strIm = util.formatNumber(this.im, math.options.precision); - - if (this.im == 0) { - // real value - str = strRe; - } - else if (this.re == 0) { - // purely complex value - if (this.im == 1) { - str = 'i'; - } - else if (this.im == -1) { - str = '-i'; - } - else { - str = strIm + 'i'; - } - } - else { - // complex value - if (this.im > 0) { - if (this.im == 1) { - str = strRe + ' + i'; - } - else { - str = strRe + ' + ' + strIm + 'i'; - } - } - else { - if (this.im == -1) { - str = strRe + ' - i'; - } - else { - str = strRe + ' - ' + - util.formatNumber(Math.abs(this.im), math.options.precision) + 'i'; - } - } - } - - return str; -}; - - -/** - * Documentation object - * @param {Object} doc Object containing properties: - * {String} name - * {String} category - * {String[]} syntax - * {String[]} examples - * {String[]} seealso - * @constructor - */ -function Help (doc) { - if (doc) { - util.extend(this, doc); - } -} - -math.type.Help = Help; - -/** - * Generate readable description from a Help object - * @return {String} readableDoc - * @private - */ -Help.prototype.toString = function () { - var desc = '\n'; - - if (this.name) { - desc += 'Name: ' + this.name + '\n\n'; - } - if (this.category) { - desc += 'Category: ' + this.category + '\n\n'; - } - if (this.syntax) { - desc += 'Syntax:\n ' + this.syntax.join('\n ') + '\n\n'; - } - if (this.examples) { - var parser = math.parser(); - desc += 'Examples:\n'; - for (var i = 0; i < this.examples.length; i++) { - var expr = this.examples[i]; - var res; - try { - res = parser.eval(expr); - } - catch (e) { - res = e; - } - desc += ' ' + expr + '\n'; - if (res && !(res instanceof Help)) { - desc += ' ' + math.format(res) + '\n'; - } - } - desc += '\n'; - } - if (this.seealso) { - desc += 'See also: ' + this.seealso.join(', ') + '\n'; - } - - - return desc; -}; - -// TODO: implement a toHTML function in Help - -/** - * Export the help object to JSON - */ -Help.prototype.toJSON = function () { - return util.extend({}, this); -}; - -/** - * @constructor Matrix - * - * A Matrix is a wrapper around an Array. A matrix can hold a multi dimensional - * array. A matrix can be constructed as: - * var matrix = new Matrix(data) - * - * Matrix contains the functions to resize, get and set values, get the size, - * clone the matrix and to convert the matrix to a vector, array, or scalar. - * Furthermore, one can iterate over the matrix using map and forEach. - * The internal Array of the Matrix can be accessed using the method valueOf. - * - * Example usage: - * var matrix = new Matrix([[1, 2], [3, 4]); - * matix.size(); // [2, 2] - * matrix.resize([3, 2], 5); - * matrix.valueOf(); // [[1, 2], [3, 4], [5, 5]] - * matrix.get([1,2]) // 3 (indexes are zero-based) - * - * @param {Array | Matrix} [data] A multi dimensional array - */ -function Matrix(data) { - if (!(this instanceof Matrix)) { - throw new SyntaxError( - 'Matrix constructor must be called with the new operator'); - } - - if (data instanceof Matrix || data instanceof Range) { - // clone data from a Matrix or Range - this._data = data.toArray(); - } - else if (Array.isArray(data)) { - // use array as is - this._data = data; - } - else if (data != null) { - // unsupported type - throw new TypeError('Unsupported type of data (' + math['typeof'](data) + ')'); - } - else { - // nothing provided - this._data = []; - } - - // verify the size of the array - this._size = util.size(this._data); -} - -math.type.Matrix = Matrix; - -/** - * Get a value or a submatrix of the matrix. - * @param {Array | Matrix} index Zero-based index - */ -Matrix.prototype.get = function (index) { - var isScalar; - if (index instanceof Matrix) { - // index is scalar when size==[n] or size==[1,1,...] - isScalar = (index.size().length == 1) || !index.size().some(function (i) { - return (i != 0); - }); - index = index.valueOf(); - } - else if (Array.isArray(index)) { - isScalar = !index.some(function (elem) { - var size = math.size(elem); - return (size.length != 0) && (size != [0]); - }); - } - else { - throw new TypeError('Invalid index'); - } - - if (index.length != this._size.length) { - throw new RangeError('Dimension mismatch ' + - '(' + index.length + ' != ' + this._size.length + ')'); - } - - if (isScalar) { - // return a single value - switch (index.length) { - case 1: return _get(this._data, index[0]); - case 2: return _get(_get(this._data, index[0]), index[1]); - default: return _getScalar(this._data, index); - } - } - else { - // return a submatrix - switch (index.length) { - case 1: return new Matrix(_getSubmatrix1D(this._data, index)); - case 2: return new Matrix(_getSubmatrix2D(this._data, index)); - default: return new Matrix(_getSubmatrix(this._data, index, 0)); - } - // TODO: more efficient when creating an empty matrix and setting _data and _size manually - } -}; - -/** - * Get a single value from an array. The method tests whether: - * - index is a non-negative integer - * - index does not exceed the dimensions of array - * @param {Array} array - * @param {Number} index Zero-based index - * @return {*} value - * @private - */ -function _get (array, index) { - util.validateIndex(index, array.length); - return array[index]; // zero-based index -} - -/** - * Get a single value from the matrix. The value will be a copy of the original - * value in the matrix. - * Index is not checked for correct number of dimensions. - * @param {Array} data - * @param {Number[]} index Zero-based index - * @return {*} scalar - * @private - */ -function _getScalar (data, index) { - index.forEach(function (i) { - data = _get(data, i); - }); - return math.clone(data); -} - -/** - * Get a submatrix of a zero dimensional matrix. - * Index is not checked for correct number of dimensions. - * @param {Array} data - * @param {Array} index Zero-based index - * @return {Array} submatrix - * @private - */ -function _getSubmatrix1D (data, index) { - var current = index[0]; - if (current.map) { - // array or Range - return current.map(function (i) { - return _get(data, i); - }); - } - else { - // scalar - return [ - _get(data, current) - ]; - } -} - -/** - * Get a submatrix of a 2 dimensional matrix. - * Index is not checked for correct number of dimensions. - * @param {Array} data - * @param {Array} index Zero-based index - * @return {Array} submatrix - * @private - */ -function _getSubmatrix2D (data, index) { - var rows = index[0]; - var cols = index[1]; - - if (rows.map) { - if (cols.map) { - return rows.map(function (row) { - var child = _get(data, row); - return cols.map(function (col) { - return _get(child, col); - }); - }); - } - else { - return rows.map(function (row) { - return [ - _get(_get(data, row), cols) - ]; - }); - } - } - else { - if (cols.map) { - var child = _get(data, rows); - return [ - cols.map(function (col) { - return _get(child, col); - }) - ] - } - else { - return [ - [ - _get(_get(data, rows), cols) - ] - ]; - } - } -} - -/** - * Get a submatrix of a multi dimensional matrix. - * Index is not checked for correct number of dimensions. - * @param {Array} data - * @param {Array} index Zero-based index - * @param {number} dim - * @return {Array} submatrix - * @private - */ -function _getSubmatrix (data, index, dim) { - var last = (dim == index.length - 1); - var current = index[dim]; - var recurse = function (i) { - var child = _get(data, i); - return last ? child : _getSubmatrix(child, index, dim + 1); - }; - - if (current.map) { - // array or Range - return current.map(recurse); - } - else { - // scalar - return [ - recurse(current) - ]; - } -} - -/** - * Replace a value or a submatrix in the matrix. - * Indexes are zero-based. - * @param {Array | Matrix} index zero-based index - * @param {*} submatrix - * @return {Matrix} itself - */ -Matrix.prototype.set = function (index, submatrix) { - var isScalar; - if (index instanceof Matrix) { - // index is scalar when size==[n] or size==[0,0,...] - isScalar = (index.size().length == 1) || !index.size().some(function (i) { - return (i != 0); - }); - index = index.valueOf(); - } - else if (Array.isArray(index)) { - isScalar = !index.some(function (elem) { - var size = math.size(elem); - return (size.length != 0) && (size != [0]); - }); - } - else { - throw new TypeError('Invalid index'); - } - - if (submatrix instanceof Matrix || submatrix instanceof Range) { - submatrix = submatrix.valueOf(); - } - - if (index.length < this._size.length) { - throw new RangeError('Dimension mismatch ' + - '(' + index.length + ' != ' + this._size.length + ')'); - } - - if (isScalar) { - // set a scalar - // check whether submatrix is no matrix/array - if (math.size(submatrix).valueOf().length != 0) { - throw new TypeError('Scalar value expected'); - } - - switch (index.length) { - case 1: _setScalar1D(this._data, this._size, index, submatrix); break; - case 2: _setScalar2D(this._data, this._size, index, submatrix); break; - default: _setScalar(this._data, this._size, index, submatrix); break; - } - } - else { - // set a submatrix - var size = this._size.concat(); - _setSubmatrix (this._data, size, index, 0, submatrix); - if (!util.deepEqual(this._size, size)) { - _init(this._data); - this.resize(size); - } - } - - return this; -}; - -/** - * Replace a single value in an array. The method tests whether index is a - * non-negative integer - * @param {Array} array - * @param {Number} index Zero-based index - * @param {*} value - * @private - */ -function _set (array, index, value) { - util.validateIndex(index); - if (Array.isArray(value)) { - throw new TypeError('Dimension mismatch, value expected instead of array'); - } - array[index] = value; // zero-based index -} - -/** - * Replace a single value in a multi dimensional matrix - * @param {Array} data - * @param {Number[]} size - * @param {Number[]} index Zero-based index - * @param {*} value - * @private - */ -function _setScalar (data, size, index, value) { - var resized = false; - if (index.length > size.length) { - // dimension added - resized = true; - } - - for (var i = 0; i < index.length; i++) { - var index_i = index[i]; - util.validateIndex(index_i); - if ((size[i] == null) || (index_i + 1 > size[i])) { - size[i] = index_i + 1; // size is index + 1 as index is zero-based - resized = true; - } - } - - if (resized) { - util.resize(data, size, 0); - } - - var len = size.length; - index.forEach(function (v, i) { - if (i < len - 1) { - data = data[v]; // zero-based index - } - else { - data[v] = value; // zero-based index - } - }); -} - -/** - * Replace a single value in a zero dimensional matrix - * @param {Array} data - * @param {Number[]} size - * @param {Number[]} index zero-based index - * @param {*} value - * @private - */ -function _setScalar1D (data, size, index, value) { - var row = index[0]; - util.validateIndex(row); - if (row + 1 > size[0]) { - util.resize(data, [row + 1], 0); // size is index + 1 as index is zero-based - size[0] = row + 1; - } - data[row] = value; // zero-based index -} - -/** - * Replace a single value in a two dimensional matrix - * @param {Array} data - * @param {Number[]} size - * @param {Number[]} index zero-based index - * @param {*} value - * @private - */ -function _setScalar2D (data, size, index, value) { - var row = index[0]; - var col = index[1]; - util.validateIndex(row); - util.validateIndex(col); - - var resized = false; - if (row + 1 > (size[0] || 0)) { - size[0] = row + 1; // size is index + 1 as index is zero-based - resized = true; - } - if (col + 1 > (size[1] || 0)) { - size[1] = col + 1; // size is index + 1 as index is zero-based - resized = true; - } - if (resized) { - util.resize(data, size, 0); - } - - data[row][col] = value; // zero-based index -} - -/** - * Replace a submatrix of a multi dimensional matrix. - * @param {Array} data - * @param {Array} size - * @param {Array} index zero-based index - * @param {number} dim - * @param {Array} submatrix - * @private - */ -function _setSubmatrix (data, size, index, dim, submatrix) { - var last = (dim == index.length - 1); - var current = index[dim]; - var recurse = function (dataIndex, subIndex) { - if (last) { - _set(data, dataIndex, submatrix[subIndex]); - if (dataIndex + 1 > (size[dim] || 0)) { - size[dim] = dataIndex + 1; - } - } - else { - var child = data[dataIndex]; // zero-based index - if (!Array.isArray(child)) { - data[dataIndex] = child = [child]; // zero-based index - } - if (dataIndex + 1 > (size[dim] || 0)) { - size[dim] = dataIndex + 1; - } - _setSubmatrix(child, size, index, dim + 1, submatrix[subIndex]); - } - }; - - if (current.map) { - // array or Range - var len = (current.size && current.size() || current.length); - if (len != submatrix.length) { - throw new RangeError('Dimensions mismatch ' + - '(' + len + ' != '+ submatrix.length + ')'); - } - current.map(recurse); - } - else { - // scalar - recurse(current, 0) - } -} - -/** - * Recursively initialize all undefined values in the array with zeros - * @param array - * @private - */ -function _init(array) { - for (var i = 0, len = array.length; i < len; i++) { - var value = array[i]; - if (Array.isArray(value)) { - _init(value); - } - else if (value == undefined) { - array[i] = 0; - } - } -} - -/** - * Resize the matrix - * @param {Number[]} size - * @param {*} [defaultValue] Default value, filled in on new entries. - * If not provided, the matrix will be filled - * with zeros. - */ -Matrix.prototype.resize = function (size, defaultValue) { - util.resize(this._data, size, defaultValue); - this._size = math.clone(size); -}; - -/** - * Create a clone of the matrix - * @return {Matrix} clone - */ -Matrix.prototype.clone = function () { - var matrix = new Matrix(); - matrix._data = math.clone(this._data); - matrix._size = math.clone(this._size); - return matrix; -}; - -/** - * Retrieve the size of the matrix. - * The size of the matrix will be validated too - * @returns {Number[]} size - */ -Matrix.prototype.size = function () { - return this._size; -}; - -/** - * Create a new matrix with the results of the callback function executed on - * each entry of the matrix. - * @param {function} callback The callback method is invoked with three - * parameters: the value of the element, the index - * of the element, and the Matrix being traversed. - * @return {Matrix} matrix - */ -Matrix.prototype.map = function (callback) { - var me = this; - var matrix = new Matrix(); - var index = []; - var recurse = function (value, dim) { - if (Array.isArray(value)) { - return value.map(function (child, i) { - index[dim] = i; // zero-based index - return recurse(child, dim + 1); - }); - } - else { - return callback(value, index, me); - } - }; - matrix._data = recurse(this._data, 0); - matrix._size = math.clone(this._size); - - return matrix; -}; - -/** - * Execute a callback method on each entry of the matrix. - * @param {function} callback The callback method is invoked with three - * parameters: the value of the element, the index - * of the element, and the Matrix being traversed. - */ -Matrix.prototype.forEach = function (callback) { - var me = this; - var index = []; - var recurse = function (value, dim) { - if (Array.isArray(value)) { - value.forEach(function (child, i) { - index[dim] = i; // zero-based index - recurse(child, dim + 1); - }); - } - else { - callback(value, index, me); - } - }; - recurse(this._data, 0); -}; - -/** - * Create a scalar with a copy of the data of the Matrix - * Will return null if the matrix does not consist of a scalar value - * @return {* | null} scalar - */ -Matrix.prototype.toScalar = function () { - var scalar = this._data; - while (Array.isArray(scalar) && scalar.length == 1) { - scalar = scalar[0]; - } - - if (Array.isArray(scalar)) { - return null; - } - else { - return math.clone(scalar); - } -}; - -/** - * Test whether the matrix is a scalar. - * @return {boolean} isScalar - */ -Matrix.prototype.isScalar = function () { - return this._size.every(function (s) { - return (s <= 1); - }); -}; - -/** - * Create a vector with a copy of the data of the Matrix - * Returns null if the Matrix does not contain a vector - * - * A matrix is a vector when it has 0 or 1 dimensions, or has multiple - * dimensions where maximum one of the dimensions has a size larger than 1. - * return {Array | null} vector - */ -Matrix.prototype.toVector = function () { - var count = 0; - var dim = undefined; - var index = []; - this._size.forEach(function (length, i) { - if (length > 1) { - count++; - dim = i; - } - index[i] = 0; - }); - - if (count == 0) { - // scalar or empty - var scalar = this.toScalar(); - if (scalar) { - return [scalar]; - } - else { - return []; - } - } - else if (count == 1) { - // valid vector - var vector = []; - var recurse = function (data) { - if (Array.isArray(data)) { - data.forEach(recurse); - } - else { - vector.push(data); - } - }; - recurse(this._data); - return vector; - } - else { - // count > 1, this is no vector - return null; - } -}; - -/** - * Test if the matrix contains a vector. - * A matrix is a vector when it has 0 or 1 dimensions, or has multiple - * dimensions where maximum one of the dimensions has a size larger than 1. - * return {boolean} isVector - */ -Matrix.prototype.isVector = function () { - var count = 0; - this._size.forEach(function (length) { - if (length > 1) { - count++; - } - }); - return (count <= 1); -}; - -/** - * Create an Array with a copy of the data of the Matrix - * @returns {Array} array - */ -Matrix.prototype.toArray = function () { - return math.clone(this._data); -}; - -/** - * Get the primitive value of the Matrix: a multidimensional array - * @returns {Array} array - */ -Matrix.prototype.valueOf = function () { - return this._data; -}; - -/** - * Get a string representation of the matrix - * @returns {String} str - */ -Matrix.prototype.toString = function () { - return math.format(this._data); -}; - -/** - * Utility functions for Numbers - */ - - -/** - * Test whether value is a Number - * @param {*} value - * @return {Boolean} isNumber - */ -function isNumber(value) { - return (value instanceof Number) || (typeof value == 'number'); -} - -/** - * Check if a number is integer - * @param {Number} value - * @return {Boolean} isInteger - */ -function isInteger(value) { - return (value == Math.round(value)); -} - -/** - * @constructor Range - * Create a range. A range works similar to an Array, with functions like - * forEach and map. However, a Range object is very cheap to create compared to - * a large Array with indexes, as it stores only a start, step and end value of - * the range. - * - * A range can be constructed as: - * var a = new Range(start, step, end); - * - * To get the result of the range: - * range.forEach(function (x) { - * console.log(x); - * }); - * range.map(function (x) { - * return math.sin(x); - * }); - * range.toArray(); - * - * Example usage: - * var c = new Range(2, 1, 5); // 2:1:5 - * c.toArray(); // [2, 3, 4, 5] - * var d = new Range(2, -1, -2); // 2:-1:-2 - * d.toArray(); // [2, 1, 0, -1, -2] - * - * @param {Number} start - * @param {Number} step - * @param {Number} end - */ -function Range(start, step, end) { - if (!(this instanceof Range)) { - throw new SyntaxError( - 'Range constructor must be called with the new operator'); - } - - if (start != null && !isNumber(start)) { - throw new TypeError('Parameter start must be a number'); - } - if (end != null && !isNumber(end)) { - throw new TypeError('Parameter end must be a number'); - } - if (step != null && !isNumber(step)) { - throw new TypeError('Parameter step must be a number'); - } - - this.start = (start != null) ? start : 0; - this.end = (end != null) ? end : 0; - this.step = (step != null) ? step : 1; -} - -math.type.Range = Range; - -/** - * Parse a string into a range, - * The string contains the start, optional step, and end, separated by a colon. - * If the string does not contain a valid range, null is returned. - * For example str='0:2:10'. - * @param {String} str - * @return {Range | null} range - */ -Range.parse = function (str) { - if (!isString(str)) { - return null; - } - - var args = str.split(':'); - var nums = args.map(function (arg) { - return Number(arg); - }); - - var invalid = nums.some(function (num) { - return isNaN(num); - }); - if(invalid) { - return null; - } - - switch (nums.length) { - case 2: return new Range(nums[0], 1, nums[1]); - case 3: return new Range(nums[0], nums[1], nums[2]); - default: return null; - } -}; - -/** - * Create a clone of the range - * @return {Range} clone - */ -Range.prototype.clone = function () { - return new Range(this.start, this.step, this.end); -}; - -/** - * Retrieve the size of the range. - * @returns {Number[]} size - */ -Range.prototype.size = function () { - var len = 0, - start = Number(this.start), - step = Number(this.step), - end = Number(this.end), - diff = end - start; - - if (math.sign(step) == math.sign(diff)) { - len = Math.floor((diff) / step) + 1; - } - else if (diff == 0) { - len = 1; - } - - if (isNaN(len)) { - len = 0; - } - return [len]; -}; - -/** - * Execute a callback function for each value in the range. - * @param {function} callback The callback method is invoked with three - * parameters: the value of the element, the index - * of the element, and the Matrix being traversed. - */ -Range.prototype.forEach = function (callback) { - var x = Number(this.start); - var step = Number(this.step); - var end = Number(this.end); - var i = 0; - - if (step > 0) { - while (x <= end) { - callback(x, i, this); - x += step; - i++; - } - } - else if (step < 0) { - while (x >= end) { - callback(x, i, this); - x += step; - i++; - } - } -}; - -/** - * Execute a callback function for each value in the Range, and return the - * results as an array - * @param {function} callback The callback method is invoked with three - * parameters: the value of the element, the index - * of the element, and the Matrix being traversed. - * @returns {Array} array - */ -Range.prototype.map = function (callback) { - var array = []; - this.forEach(function (value, index, obj) { - array[index] = callback(value, index, obj); - }); - return array; -}; - -/** - * Create a Matrix with a copy of the Ranges data - * @return {Matrix} matrix - */ -Range.prototype.toMatrix = function () { - return new Matrix(this.toArray()); -}; - -/** - * Create an Array with a copy of the Ranges data - * @returns {Array} array - */ -Range.prototype.toArray = function () { - var array = []; - this.forEach(function (value, index) { - array[index] = value; - }); - return array; -}; - -/** - * Create an array with a copy of the Ranges data. - * This method is equal to Range.toArray, and is available for compatibility - * with Matrix. - * @return {Array} vector - */ -Range.prototype.toVector = Range.prototype.toArray; - -/** - * Test if the range contains a vector. For a range, this is always the case - * return {boolean} isVector - */ -Range.prototype.isVector = function () { - return true; -}; - -/** - * Create a scalar with a copy of the data of the Range - * Will return null if the range does not consist of a scalar value - * @return {* | null} scalar - */ -Range.prototype.toScalar = function () { - var array = this.toArray(); - if (array.length == 1) { - return array[0]; - } - else { - return null; - } -}; - -/** - * Test whether the matrix is a scalar. - * @return {boolean} isScalar - */ -Range.prototype.isScalar = function () { - return (this.size()[0] == 1); -}; - -/** - * Get the primitive value of the Range, a one dimensional array - * @returns {Array} array - */ -Range.prototype.valueOf = function () { - // TODO: implement a caching mechanism for range.valueOf() - return this.toArray(); -}; - -/** - * Get the string representation of the range, for example '2:5' or '0:0.2:10' - * @returns {String} str - */ -Range.prototype.toString = function () { - var str = math.format(Number(this.start)); - if (this.step != 1) { - str += ':' + math.format(Number(this.step)); - } - str += ':' + math.format(Number(this.end)); - return str; -}; - -/** - * @constructor math.type.Selector - * Wrap any value in a Selector, allowing to perform chained operations on - * the value. - * - * All methods available in the math.js library can be called upon the selector, - * and then will be evaluated with the value itself as first argument. - * The selector can be closed by executing selector.done(), which will return - * the final value. - * - * The Selector has a number of special functions: - * - done() Finalize the chained operation and return the selectors value. - * - valueOf() The same as done() - * - toString() Executes math.format() onto the selectors value, returning - * a string representation of the value. - * - get(...) Get a subset of the selectors value. Useful for example for - * matrices and arrays. - * - set(...) Replace a subset of the selectors value. Useful for example for - * matrices and arrays. - * - * @param {*} [value] - */ -math.type.Selector = function Selector (value) { - if (!(this instanceof math.type.Selector)) { - throw new SyntaxError( - 'Selector constructor must be called with the new operator'); - } - - if (value instanceof math.type.Selector) { - this.value = value.value; - } - else { - this.value = value; - } -}; - -math.type.Selector.prototype = { - /** - * Close the selector. Returns the final value. - * Does the same as method valueOf() - * @returns {*} value - */ - done: function () { - return this.value; - }, - - /** - * Get a submatrix or subselection from current value. - * Only applicable when the current value has a method get. - */ - get: function (index) { - var value = this.value; - if (!value) { - throw Error('Selector value is undefined'); - } - - return new math.type.Selector(math.subset(value, index)); - }, - - /** - * Set a submatrix or subselection on current value. - * Only applicable when the current value has a method set. - */ - set: function (index, replacement) { - var value = this.value; - if (!value) { - throw Error('Selector value is undefined'); - } - - return new math.type.Selector(math.subset(value, index, replacement)); - }, - - /** - * Close the selector. Returns the final value. - * Does the same as method done() - * @returns {*} value - */ - valueOf: function () { - return this.value; - }, - - /** - * Get the string representation of the value in the selector - * @returns {String} - */ - toString: function () { - return math.format(this.value); - } -}; - -/** - * Create a proxy method for the selector - * @param {String} name - * @param {*} value The value or function to be proxied - */ -function createSelectorProxy(name, value) { - var Selector = math.type.Selector; - var slice = Array.prototype.slice; - if (typeof value === 'function') { - // a function - Selector.prototype[name] = function () { - var args = [this.value].concat(slice.call(arguments, 0)); - return new Selector(value.apply(this, args)); - } - } - else { - // a constant - Selector.prototype[name] = new Selector(value); - } -} - -/** - * Utility functions for Strings - */ - -/** - * Test whether value is a String - * @param {*} value - * @return {Boolean} isString - */ -function isString(value) { - return (value instanceof String) || (typeof value == 'string'); -} - -/** - * @constructor Unit - * - * A unit can be constructed in the following ways: - * var a = new Unit(value, unit); - * var b = new Unit(null, unit); - * var c = Unit.parse(str); - * - * Example usage: - * var a = new Unit(5, 'cm'); // 50 mm - * var b = Unit.parse('23 kg'); // 23 kg - * var c = math.in(a, new Unit(null, 'm'); // 0.05 m - * - * @param {Number} [value] A value like 5.2 - * @param {String} [unit] A unit like "cm" or "inch" - */ -function Unit(value, unit) { - if (!(this instanceof Unit)) { - throw new Error('Unit constructor must be called with the new operator'); - } - - if (value != null && !isNumber(value)) { - throw new TypeError('First parameter in Unit constructor must be a number'); - } - if (unit != null && !isString(unit)) { - throw new TypeError('Second parameter in Unit constructor must be a string'); - } - - if (unit != null) { - // find the unit and prefix from the string - var res = _findUnit(unit); - if (!res) { - throw new SyntaxError('String "' + unit + '" is no unit'); - } - this.unit = res.unit; - this.prefix = res.prefix; - } - else { - this.unit = Unit.UNIT_NONE; - this.prefix = Unit.PREFIX_NONE; // link to a list with supported prefixes - } - - if (value != null) { - this.value = this._normalize(value); - this.fixPrefix = false; // is set true by the methods Unit.in and math.in - } - else { - this.value = null; - this.fixPrefix = true; - } -} - -math.type.Unit = Unit; - -(function() { - var text, index, c; - - function skipWhitespace() { - while (c == ' ' || c == '\t') { - next(); - } - } - - function isDigitDot (c) { - return ((c >= '0' && c <= '9') || c == '.'); - } - - function isDigit (c) { - return ((c >= '0' && c <= '9')); - } - - function next() { - index++; - c = text.charAt(index); - } - - function revert(oldIndex) { - index = oldIndex; - c = text.charAt(index); - } - - function parseNumber () { - var number = ''; - var oldIndex; - oldIndex = index; - - if (c == '+') { - next(); - } - else if (c == '-') { - number += c; - next(); - } - - if (!isDigitDot(c)) { - // a + or - must be followed by a digit - revert(oldIndex); - return null; - } - - // get number, can have a single dot - if (c == '.') { - number += c; - next(); - if (!isDigit(c)) { - // this is no legal number, it is just a dot - revert(oldIndex); - return null; - } - } - else { - while (isDigit(c)) { - number += c; - next(); - } - if (c == '.') { - number += c; - next(); - } - } - while (isDigit(c)) { - number += c; - next(); - } - - // check for scientific notation like "2.3e-4" or "1.23e50" - if (c == 'E' || c == 'e') { - number += c; - next(); - - if (c == '+' || c == '-') { - number += c; - next(); - } - - // Scientific notation MUST be followed by an exponent - if (!isDigit(c)) { - // this is no legal number, exponent is missing. - revert(oldIndex); - return null; - } - - while (isDigit(c)) { - number += c; - next(); - } - } - - return number; - } - - function parseUnit() { - var unit = ''; - - skipWhitespace(); - while (c && c != ' ' && c != '\t') { - unit += c; - next(); - } - - return unit || null; - } - - /** - * Parse a string into a unit. Returns null if the provided string does not - * contain a valid unit. - * @param {String} str A string like "5.2 inch", "4e2 kg" - * @return {Unit | null} unit - */ - Unit.parse = function parse(str) { - text = str; - index = -1; - c = ''; - - if (!isString(text)) { - return null; - } - - next(); - skipWhitespace(); - var value = parseNumber(); - var unit; - if (value) { - unit = parseUnit(); - - next(); - skipWhitespace(); - if (c) { - // garbage at the end. not good. - return null; - } - - if (value && unit) { - return new Unit(Number(value), unit); - } - } - else { - unit = parseUnit(); - - next(); - skipWhitespace(); - if (c) { - // garbage at the end. not good. - return null; - } - - return new Unit(null, unit) - } - - return null; - }; - -})(); - -/** - * Test whether value is of type Unit - * @param {*} value - * @return {Boolean} isUnit - */ -function isUnit(value) { - return (value instanceof Unit); -} - -/** - * create a copy of this unit - * @return {Unit} clone - */ -Unit.prototype.clone = function () { - var clone = new Unit(); - - for (var p in this) { - if (this.hasOwnProperty(p)) { - clone[p] = this[p]; - } - } - - return clone; -}; - -/** - * Normalize a value, based on its currently set unit - * @param {Number} value - * @return {Number} normalized value - * @private - */ -Unit.prototype._normalize = function(value) { - return (value + this.unit.offset) * - this.unit.value * this.prefix.value; -}; - -/** - * Unnormalize a value, based on its currently set unit - * @param {Number} value - * @param {Number} [prefixValue] Optional prefix value to be used - * @return {Number} unnormalized value - * @private - */ -Unit.prototype._unnormalize = function (value, prefixValue) { - if (prefixValue == undefined) { - return value / this.unit.value / this.prefix.value - - this.unit.offset; - } - else { - return value / this.unit.value / prefixValue - - this.unit.offset; - } -}; - -/** - * Find a unit from a string - * @param {String} str A string like 'cm' or 'inch' - * @returns {Object | null} result When found, an object with fields unit and - * prefix is returned. Else, null is returned. - * @private - */ -function _findUnit(str) { - var UNITS = Unit.UNITS; - for (var i = 0, iMax = UNITS.length; i < iMax; i++) { - var UNIT = UNITS[i]; - - if (util.endsWith(str, UNIT.name) ) { - var prefixLen = (str.length - UNIT.name.length); - var prefixName = str.substring(0, prefixLen); - var prefix = UNIT.prefixes[prefixName]; - if (prefix !== undefined) { - // store unit, prefix, and value - return { - unit: UNIT, - prefix: prefix - }; - } - } - } - - return null; -} - -/** - * Test if the given expression is a unit. - * The unit can have a prefix but cannot have a value. - * @param {String} unit A plain unit without value. Can have prefix, like "cm" - * @return {Boolean} true if the given string is a unit - */ -Unit.isPlainUnit = function (unit) { - return (_findUnit(unit) != null); -}; - -/** - * check if this unit has given base unit - * @param {Unit.BASE_UNITS} base - */ -Unit.prototype.hasBase = function(base) { - if (this.unit.base === undefined) { - return (base === undefined); - } - return (this.unit.base === base); -}; - -/** - * Check if this unit has a base equal to another base - * @param {Unit} other - * @return {Boolean} true if equal base - */ -Unit.prototype.equalBase = function(other) { - return (this.unit.base === other.unit.base); -}; - -/** - * Check if this unit equals another unit - * @param {Unit} other - * @return {Boolean} true if both units are equal - */ -Unit.prototype.equals = function(other) { - return (this.equalBase(other) && this.value == other.value); -}; - -/** - * Create a clone of this unit with a representation - * @param {String | Unit} plainUnit A plain unit, without value. Can have prefix, like "cm" - * @returns {Unit} unit having fixed, specified unit - */ -Unit.prototype['in'] = function (plainUnit) { - var other; - if (isString(plainUnit)) { - other = new Unit(null, plainUnit); - - if (!this.equalBase(other)) { - throw new Error('Units do not match'); - } - - other.value = this.value; - return other; - } - else if (plainUnit instanceof Unit) { - if (!this.equalBase(plainUnit)) { - throw new Error('Units do not match'); - } - if (plainUnit.value != null) { - throw new Error('Cannot convert to a unit with a value'); - } - if (plainUnit.unit == null) { - throw new Error('Unit expected on the right hand side of function in'); - } - - other = plainUnit.clone(); - other.value = this.value; - other.fixPrefix = true; - return other; - } - else { - throw new Error('String or Unit expected as parameter'); - } -}; - -/** - * Return the value of the unit when represented with given plain unit - * @param {String | Unit} plainUnit For example 'cm' or 'inch' - * @return {Number} value - */ -Unit.prototype.toNumber = function (plainUnit) { - var other = this['in'](plainUnit); - var prefix = this.fixPrefix ? other._bestPrefix() : other.prefix; - return other._unnormalize(other.value, prefix.value); -}; - -/** - * Get string representation - * @return {String} - */ -Unit.prototype.toString = function() { - var value, str; - if (!this.fixPrefix) { - var bestPrefix = this._bestPrefix(); - value = this._unnormalize(this.value, bestPrefix.value); - str = (this.value != null) ? util.formatNumber(value, math.options.precision) + ' ' : ''; - str += bestPrefix.name + this.unit.name; - } - else { - value = this._unnormalize(this.value); - str = (this.value != null) ? util.formatNumber(value, math.options.precision) + ' ' : ''; - str += this.prefix.name + this.unit.name; - } - return str; -}; - -/** - * Calculate the best prefix using current value. - * @returns {Object} prefix - * @private - */ -Unit.prototype._bestPrefix = function () { - // find the best prefix value (resulting in the value of which - // the absolute value of the log10 is closest to zero, - // though with a little offset of 1.2 for nicer values: you get a - // sequence 1mm 100mm 500mm 0.6m 1m 10m 100m 500m 0.6km 1km ... - var absValue = Math.abs(this.value / this.unit.value); - var bestPrefix = Unit.PREFIX_NONE; - var bestDiff = Math.abs( - Math.log(absValue / bestPrefix.value) / Math.LN10 - 1.2); - - var prefixes = this.unit.prefixes; - for (var p in prefixes) { - if (prefixes.hasOwnProperty(p)) { - var prefix = prefixes[p]; - if (prefix.scientific) { - var diff = Math.abs( - Math.log(absValue / prefix.value) / Math.LN10 - 1.2); - - if (diff < bestDiff) { - bestPrefix = prefix; - bestDiff = diff; - } - } - } - } - - return bestPrefix; -}; - -Unit.PREFIXES = { - 'NONE': { - '': {'name': '', 'value': 1, 'scientific': true} - }, - 'SHORT': { - '': {'name': '', 'value': 1, 'scientific': true}, - - 'da': {'name': 'da', 'value': 1e1, 'scientific': false}, - 'h': {'name': 'h', 'value': 1e2, 'scientific': false}, - 'k': {'name': 'k', 'value': 1e3, 'scientific': true}, - 'M': {'name': 'M', 'value': 1e6, 'scientific': true}, - 'G': {'name': 'G', 'value': 1e9, 'scientific': true}, - 'T': {'name': 'T', 'value': 1e12, 'scientific': true}, - 'P': {'name': 'P', 'value': 1e15, 'scientific': true}, - 'E': {'name': 'E', 'value': 1e18, 'scientific': true}, - 'Z': {'name': 'Z', 'value': 1e21, 'scientific': true}, - 'Y': {'name': 'Y', 'value': 1e24, 'scientific': true}, - - 'd': {'name': 'd', 'value': 1e-1, 'scientific': false}, - 'c': {'name': 'c', 'value': 1e-2, 'scientific': false}, - 'm': {'name': 'm', 'value': 1e-3, 'scientific': true}, - // 'µ': {'name': 'µ', 'value': 1e-6, 'scientific': true}, - 'u': {'name': 'u', 'value': 1e-6, 'scientific': true}, - 'n': {'name': 'n', 'value': 1e-9, 'scientific': true}, - 'p': {'name': 'p', 'value': 1e-12, 'scientific': true}, - 'f': {'name': 'f', 'value': 1e-15, 'scientific': true}, - 'a': {'name': 'a', 'value': 1e-18, 'scientific': true}, - 'z': {'name': 'z', 'value': 1e-21, 'scientific': true}, - 'y': {'name': 'y', 'value': 1e-24, 'scientific': true} - }, - 'LONG': { - '': {'name': '', 'value': 1, 'scientific': true}, - - 'deca': {'name': 'deca', 'value': 1e1, 'scientific': false}, - 'hecto': {'name': 'hecto', 'value': 1e2, 'scientific': false}, - 'kilo': {'name': 'kilo', 'value': 1e3, 'scientific': true}, - 'mega': {'name': 'mega', 'value': 1e6, 'scientific': true}, - 'giga': {'name': 'giga', 'value': 1e9, 'scientific': true}, - 'tera': {'name': 'tera', 'value': 1e12, 'scientific': true}, - 'peta': {'name': 'peta', 'value': 1e15, 'scientific': true}, - 'exa': {'name': 'exa', 'value': 1e18, 'scientific': true}, - 'zetta': {'name': 'zetta', 'value': 1e21, 'scientific': true}, - 'yotta': {'name': 'yotta', 'value': 1e24, 'scientific': true}, - - 'deci': {'name': 'deci', 'value': 1e-1, 'scientific': false}, - 'centi': {'name': 'centi', 'value': 1e-2, 'scientific': false}, - 'milli': {'name': 'milli', 'value': 1e-3, 'scientific': true}, - 'micro': {'name': 'micro', 'value': 1e-6, 'scientific': true}, - 'nano': {'name': 'nano', 'value': 1e-9, 'scientific': true}, - 'pico': {'name': 'pico', 'value': 1e-12, 'scientific': true}, - 'femto': {'name': 'femto', 'value': 1e-15, 'scientific': true}, - 'atto': {'name': 'atto', 'value': 1e-18, 'scientific': true}, - 'zepto': {'name': 'zepto', 'value': 1e-21, 'scientific': true}, - 'yocto': {'name': 'yocto', 'value': 1e-24, 'scientific': true} - }, - 'BINARY_SHORT': { - '': {'name': '', 'value': 1, 'scientific': true}, - 'k': {'name': 'k', 'value': 1024, 'scientific': true}, - 'M': {'name': 'M', 'value': Math.pow(1024, 2), 'scientific': true}, - 'G': {'name': 'G', 'value': Math.pow(1024, 3), 'scientific': true}, - 'T': {'name': 'T', 'value': Math.pow(1024, 4), 'scientific': true}, - 'P': {'name': 'P', 'value': Math.pow(1024, 5), 'scientific': true}, - 'E': {'name': 'E', 'value': Math.pow(1024, 6), 'scientific': true}, - 'Z': {'name': 'Z', 'value': Math.pow(1024, 7), 'scientific': true}, - 'Y': {'name': 'Y', 'value': Math.pow(1024, 8), 'scientific': true}, - - 'Ki': {'name': 'Ki', 'value': 1024, 'scientific': true}, - 'Mi': {'name': 'Mi', 'value': Math.pow(1024, 2), 'scientific': true}, - 'Gi': {'name': 'Gi', 'value': Math.pow(1024, 3), 'scientific': true}, - 'Ti': {'name': 'Ti', 'value': Math.pow(1024, 4), 'scientific': true}, - 'Pi': {'name': 'Pi', 'value': Math.pow(1024, 5), 'scientific': true}, - 'Ei': {'name': 'Ei', 'value': Math.pow(1024, 6), 'scientific': true}, - 'Zi': {'name': 'Zi', 'value': Math.pow(1024, 7), 'scientific': true}, - 'Yi': {'name': 'Yi', 'value': Math.pow(1024, 8), 'scientific': true} - }, - 'BINARY_LONG': { - '': {'name': '', 'value': 1, 'scientific': true}, - 'kilo': {'name': 'kilo', 'value': 1024, 'scientific': true}, - 'mega': {'name': 'mega', 'value': Math.pow(1024, 2), 'scientific': true}, - 'giga': {'name': 'giga', 'value': Math.pow(1024, 3), 'scientific': true}, - 'tera': {'name': 'tera', 'value': Math.pow(1024, 4), 'scientific': true}, - 'peta': {'name': 'peta', 'value': Math.pow(1024, 5), 'scientific': true}, - 'exa': {'name': 'exa', 'value': Math.pow(1024, 6), 'scientific': true}, - 'zetta': {'name': 'zetta', 'value': Math.pow(1024, 7), 'scientific': true}, - 'yotta': {'name': 'yotta', 'value': Math.pow(1024, 8), 'scientific': true}, - - 'kibi': {'name': 'kibi', 'value': 1024, 'scientific': true}, - 'mebi': {'name': 'mebi', 'value': Math.pow(1024, 2), 'scientific': true}, - 'gibi': {'name': 'gibi', 'value': Math.pow(1024, 3), 'scientific': true}, - 'tebi': {'name': 'tebi', 'value': Math.pow(1024, 4), 'scientific': true}, - 'pebi': {'name': 'pebi', 'value': Math.pow(1024, 5), 'scientific': true}, - 'exi': {'name': 'exi', 'value': Math.pow(1024, 6), 'scientific': true}, - 'zebi': {'name': 'zebi', 'value': Math.pow(1024, 7), 'scientific': true}, - 'yobi': {'name': 'yobi', 'value': Math.pow(1024, 8), 'scientific': true} - } -}; - -Unit.PREFIX_NONE = {'name': '', 'value': 1, 'scientific': true}; - -Unit.BASE_UNITS = { - 'NONE': {}, - - 'LENGTH': {}, // meter - 'MASS': {}, // kilogram - 'TIME': {}, // second - 'CURRENT': {}, // ampere - 'TEMPERATURE': {}, // kelvin - 'LUMINOUS_INTENSITY': {}, // candela - 'AMOUNT_OF_SUBSTANCE': {}, // mole - - 'FORCE': {}, // Newton - 'SURFACE': {}, // m2 - 'VOLUME': {}, // m3 - 'ANGLE': {}, // rad - 'BIT': {} // bit (digital) -}; - -var BASE_UNITS = Unit.BASE_UNITS; -var PREFIXES = Unit.PREFIXES; - -Unit.BASE_UNIT_NONE = {}; - -Unit.UNIT_NONE = {'name': '', 'base': Unit.BASE_UNIT_NONE, 'value': 1, 'offset': 0}; - -Unit.UNITS = [ - // length - {'name': 'meter', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.LONG, 'value': 1, 'offset': 0}, - {'name': 'inch', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.0254, 'offset': 0}, - {'name': 'foot', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.3048, 'offset': 0}, - {'name': 'yard', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.9144, 'offset': 0}, - {'name': 'mile', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 1609.344, 'offset': 0}, - {'name': 'link', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.201168, 'offset': 0}, - {'name': 'rod', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 5.029210, 'offset': 0}, - {'name': 'chain', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 20.1168, 'offset': 0}, - {'name': 'angstrom', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 1e-10, 'offset': 0}, - - {'name': 'm', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.SHORT, 'value': 1, 'offset': 0}, - //{'name': 'in', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.0254, 'offset': 0}, not supported, In is an operator - {'name': 'ft', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.3048, 'offset': 0}, - {'name': 'yd', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.9144, 'offset': 0}, - {'name': 'mi', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 1609.344, 'offset': 0}, - {'name': 'li', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.201168, 'offset': 0}, - {'name': 'rd', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 5.029210, 'offset': 0}, - {'name': 'ch', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 20.1168, 'offset': 0}, - {'name': 'mil', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.0000254, 'offset': 0}, // 1/1000 inch - - // Surface - {'name': 'm2', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.SHORT, 'value': 1, 'offset': 0}, - {'name': 'sqin', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.NONE, 'value': 0.00064516, 'offset': 0}, // 645.16 mm2 - {'name': 'sqft', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.NONE, 'value': 0.09290304, 'offset': 0}, // 0.09290304 m2 - {'name': 'sqyd', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.NONE, 'value': 0.83612736, 'offset': 0}, // 0.83612736 m2 - {'name': 'sqmi', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.NONE, 'value': 2589988.110336, 'offset': 0}, // 2.589988110336 km2 - {'name': 'sqrd', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.NONE, 'value': 25.29295, 'offset': 0}, // 25.29295 m2 - {'name': 'sqch', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.NONE, 'value': 404.6873, 'offset': 0}, // 404.6873 m2 - {'name': 'sqmil', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.NONE, 'value': 6.4516e-10, 'offset': 0}, // 6.4516 * 10^-10 m2 - - // Volume - {'name': 'm3', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.SHORT, 'value': 1, 'offset': 0}, - {'name': 'L', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.SHORT, 'value': 0.001, 'offset': 0}, // litre - {'name': 'litre', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.LONG, 'value': 0.001, 'offset': 0}, - {'name': 'cuin', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 1.6387064e-5, 'offset': 0}, // 1.6387064e-5 m3 - {'name': 'cuft', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.028316846592, 'offset': 0}, // 28.316 846 592 L - {'name': 'cuyd', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.764554857984, 'offset': 0}, // 764.554 857 984 L - {'name': 'teaspoon', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.000005, 'offset': 0}, // 5 mL - {'name': 'tablespoon', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.000015, 'offset': 0}, // 15 mL - //{'name': 'cup', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.000240, 'offset': 0}, // 240 mL // not possible, we have already another cup - - // Liquid volume - {'name': 'minim', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.00000006161152, 'offset': 0}, // 0.06161152 mL - {'name': 'fluiddram', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0000036966911, 'offset': 0}, // 3.696691 mL - {'name': 'fluidounce', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.00002957353, 'offset': 0}, // 29.57353 mL - {'name': 'gill', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0001182941, 'offset': 0}, // 118.2941 mL - {'name': 'cup', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0002365882, 'offset': 0}, // 236.5882 mL - {'name': 'pint', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0004731765, 'offset': 0}, // 473.1765 mL - {'name': 'quart', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0009463529, 'offset': 0}, // 946.3529 mL - {'name': 'gallon', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.003785412, 'offset': 0}, // 3.785412 L - {'name': 'beerbarrel', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.1173478, 'offset': 0}, // 117.3478 L - {'name': 'oilbarrel', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.1589873, 'offset': 0}, // 158.9873 L - {'name': 'hogshead', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.2384810, 'offset': 0}, // 238.4810 L - - //{'name': 'min', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.00000006161152, 'offset': 0}, // 0.06161152 mL // min is already in use as minute - {'name': 'fldr', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0000036966911, 'offset': 0}, // 3.696691 mL - {'name': 'floz', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.00002957353, 'offset': 0}, // 29.57353 mL - {'name': 'gi', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0001182941, 'offset': 0}, // 118.2941 mL - {'name': 'cp', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0002365882, 'offset': 0}, // 236.5882 mL - {'name': 'pt', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0004731765, 'offset': 0}, // 473.1765 mL - {'name': 'qt', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0009463529, 'offset': 0}, // 946.3529 mL - {'name': 'gal', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.003785412, 'offset': 0}, // 3.785412 L - {'name': 'bbl', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.1173478, 'offset': 0}, // 117.3478 L - {'name': 'obl', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.1589873, 'offset': 0}, // 158.9873 L - //{'name': 'hogshead', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.2384810, 'offset': 0}, // 238.4810 L // TODO: hh? - - // Mass - {'name': 'g', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.SHORT, 'value': 0.001, 'offset': 0}, - {'name': 'gram', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.LONG, 'value': 0.001, 'offset': 0}, - - {'name': 'ton', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.SHORT, 'value': 907.18474, 'offset': 0}, - {'name': 'tonne', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.SHORT, 'value': 1000, 'offset': 0}, - - {'name': 'grain', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 64.79891e-6, 'offset': 0}, - {'name': 'dram', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 1.7718451953125e-3, 'offset': 0}, - {'name': 'ounce', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 28.349523125e-3, 'offset': 0}, - {'name': 'poundmass', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 453.59237e-3, 'offset': 0}, - {'name': 'hundredweight', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 45.359237, 'offset': 0}, - {'name': 'stick', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 115e-3, 'offset': 0}, - - {'name': 'gr', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 64.79891e-6, 'offset': 0}, - {'name': 'dr', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 1.7718451953125e-3, 'offset': 0}, - {'name': 'oz', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 28.349523125e-3, 'offset': 0}, - {'name': 'lbm', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 453.59237e-3, 'offset': 0}, - {'name': 'cwt', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 45.359237, 'offset': 0}, - - // Time - {'name': 's', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.SHORT, 'value': 1, 'offset': 0}, - {'name': 'min', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 60, 'offset': 0}, - {'name': 'h', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 3600, 'offset': 0}, - {'name': 'seconds', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.LONG, 'value': 1, 'offset': 0}, - {'name': 'second', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.LONG, 'value': 1, 'offset': 0}, - {'name': 'sec', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.LONG, 'value': 1, 'offset': 0}, - {'name': 'minutes', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 60, 'offset': 0}, - {'name': 'minute', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 60, 'offset': 0}, - {'name': 'hours', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 3600, 'offset': 0}, - {'name': 'hour', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 3600, 'offset': 0}, - {'name': 'day', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 86400, 'offset': 0}, - {'name': 'days', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 86400, 'offset': 0}, - - // Angles - {'name': 'rad', 'base': BASE_UNITS.ANGLE, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0}, - {'name': 'deg', 'base': BASE_UNITS.ANGLE, 'prefixes': PREFIXES.NONE, 'value': 0.017453292519943295769236907684888, 'offset': 0}, // deg = rad / (2*pi) * 360 = rad / 0.017453292519943295769236907684888 - {'name': 'grad', 'base': BASE_UNITS.ANGLE, 'prefixes': PREFIXES.NONE, 'value': 0.015707963267948966192313216916399, 'offset': 0}, // grad = rad / (2*pi) * 400 = rad / 0.015707963267948966192313216916399 - {'name': 'cycle', 'base': BASE_UNITS.ANGLE, 'prefixes': PREFIXES.NONE, 'value': 6.2831853071795864769252867665793, 'offset': 0}, // cycle = rad / (2*pi) = rad / 6.2831853071795864769252867665793 - - // Electric current - {'name': 'A', 'base': BASE_UNITS.CURRENT, 'prefixes': PREFIXES.SHORT, 'value': 1, 'offset': 0}, - {'name': 'ampere', 'base': BASE_UNITS.CURRENT, 'prefixes': PREFIXES.LONG, 'value': 1, 'offset': 0}, - - // Temperature - // K(C) = °C + 273.15 - // K(F) = (°F + 459.67) / 1.8 - // K(R) = °R / 1.8 - {'name': 'K', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0}, - {'name': 'degC', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 273.15}, - {'name': 'degF', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1/1.8, 'offset': 459.67}, - {'name': 'degR', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1/1.8, 'offset': 0}, - {'name': 'kelvin', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0}, - {'name': 'celsius', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 273.15}, - {'name': 'fahrenheit', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1/1.8, 'offset': 459.67}, - {'name': 'rankine', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1/1.8, 'offset': 0}, - - // amount of substance - {'name': 'mol', 'base': BASE_UNITS.AMOUNT_OF_SUBSTANCE, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0}, - {'name': 'mole', 'base': BASE_UNITS.AMOUNT_OF_SUBSTANCE, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0}, - - // luminous intensity - {'name': 'cd', 'base': BASE_UNITS.LUMINOUS_INTENSITY, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0}, - {'name': 'candela', 'base': BASE_UNITS.LUMINOUS_INTENSITY, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0}, - // TODO: units STERADIAN - //{'name': 'sr', 'base': BASE_UNITS.STERADIAN, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0}, - //{'name': 'steradian', 'base': BASE_UNITS.STERADIAN, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0}, - - // Force - {'name': 'N', 'base': BASE_UNITS.FORCE, 'prefixes': PREFIXES.SHORT, 'value': 1, 'offset': 0}, - {'name': 'newton', 'base': BASE_UNITS.FORCE, 'prefixes': PREFIXES.LONG, 'value': 1, 'offset': 0}, - {'name': 'lbf', 'base': BASE_UNITS.FORCE, 'prefixes': PREFIXES.NONE, 'value': 4.4482216152605, 'offset': 0}, - {'name': 'poundforce', 'base': BASE_UNITS.FORCE, 'prefixes': PREFIXES.NONE, 'value': 4.4482216152605, 'offset': 0}, - - // Binary - {'name': 'b', 'base': BASE_UNITS.BIT, 'prefixes': PREFIXES.BINARY_SHORT, 'value': 1, 'offset': 0}, - {'name': 'bits', 'base': BASE_UNITS.BIT, 'prefixes': PREFIXES.BINARY_LONG, 'value': 1, 'offset': 0}, - {'name': 'B', 'base': BASE_UNITS.BIT, 'prefixes': PREFIXES.BINARY_SHORT, 'value': 8, 'offset': 0}, - {'name': 'bytes', 'base': BASE_UNITS.BIT, 'prefixes': PREFIXES.BINARY_LONG, 'value': 8, 'offset': 0} -]; - -/** - * mathjs constants - */ -math.pi = Math.PI; -math.e = Math.E; -math.tau = Math.PI * 2; -math.i = new Complex(0, 1); - -math['Infinity']= Infinity; -math['NaN'] = NaN; -math['true'] = true; -math['false'] = false; - -// uppercase constants (for compatibility with built-in Math) -math.E = Math.E; -math.LN2 = Math.LN2; -math.LN10 = Math.LN10; -math.LOG2E = Math.LOG2E; -math.LOG10E = Math.LOG10E; -math.PI = Math.PI; -math.SQRT1_2 = Math.SQRT1_2; -math.SQRT2 = Math.SQRT2; - -/** - * Helper methods for functions - */ - -/** - * Create a TypeError with message: - * 'Function does not support a parameter of type '; - * @param {String} name Function name - * @param {*} value1 - * @param {*} [value2] - * @return {TypeError | Error} error - */ -function newUnsupportedTypeError(name, value1, value2) { - var msg = undefined; - if (arguments.length == 2) { - var t = math['typeof'](value1); - msg = 'Function ' + name + '(' + t + ') not supported'; - } - else if (arguments.length > 2) { - var types = []; - for (var i = 1; i < arguments.length; i++) { - types.push(math['typeof'](arguments[i])); - } - msg = 'Function ' + name + '(' + types.join(', ') + ') not supported'; - } - else { - msg = 'Unsupported parameter in function ' + name; - } - - return new TypeError(msg); -} - -/** - * Create a syntax error with the message: - * 'Wrong number of arguments in function ( provided, - expected)' - * @param {String} name Function name - * @param {Number} count Actual argument count - * @param {Number} min Minimum required argument count - * @param {Number} [max] Maximum required argument count - */ -function newArgumentsError(name, count, min, max) { - var msg = 'Wrong number of arguments in function ' + name + - ' (' + count + ' provided, ' + - min + ((max != undefined) ? ('-' + max) : '') + ' expected)'; - return new SyntaxError(msg); -} - -/** - * Node - */ -function Node() {} - -math.expr.node.Node = Node; - -/** - * Evaluate the node - * @return {*} result - */ -Node.prototype.eval = function () { - throw new Error('Cannot evaluate a Node interface'); -}; - -/** - * Find any node in the node tree matching given filter. For example, to - * find all nodes of type SymbolNode having name 'x': - * - * var results = Node.find({ - * type: SymbolNode, - * properties: { - * name: 'x' - * } - * }); - * - * @param {Object} filter Available parameters: - * {Function} type - * {Object} properties - * @return {Node[]} nodes An array with nodes matching given filter criteria - */ -Node.prototype.find = function (filter) { - return this.match(filter) ? [this] : []; -}; - -/** - * Test if this object matches given filter - * @param {Object} filter Available parameters: - * {Function} type - * {Object} properties - * @return {Boolean} matches True if there is a match - */ -Node.prototype.match = function (filter) { - var match = true; - - if (filter) { - if (filter.type && !(this instanceof filter.type)) { - match = false; - } - if (match && filter.properties) { - for (var prop in filter.properties) { - if (filter.properties.hasOwnProperty(prop)) { - if (this[prop] != filter.properties[prop]) { - match = false; - break; - } - } - } - } - } - - return match; -}; - -/** - * Get string representation - * @return {String} - */ -Node.prototype.toString = function() { - return ''; -}; - -/** - * @constructor ConstantNode - * @param {*} value - * @extends {Node} - */ -function ConstantNode(value) { - this.value = value; -} - -ConstantNode.prototype = new Node(); - -math.expr.node.ConstantNode = ConstantNode; - -/** - * Evaluate the constant (just return it) - * @return {*} value - */ -ConstantNode.prototype.eval = function () { - return this.value; -}; - -/** - * Get string representation - * @return {String} str - */ -ConstantNode.prototype.toString = function() { - return math.format(this.value); -}; - -/** - * @constructor OperatorNode - * An operator with two arguments, like 2+3 - * @param {String} name Function name, for example '+' - * @param {function} fn Function, for example math.add - * @param {Node[]} params Parameters - */ -function OperatorNode (name, fn, params) { - this.name = name; - this.fn = fn; - this.params = params; -} - -OperatorNode.prototype = new Node(); - -math.expr.node.OperatorNode = OperatorNode; - -/** - * Evaluate the parameters - * @return {*} result - */ -OperatorNode.prototype.eval = function() { - return this.fn.apply(this, this.params.map(function (param) { - return param.eval(); - })); -}; - -/** - * Find all nodes matching given filter - * @param {Object} filter See Node.find for a description of the filter options - * @returns {Node[]} nodes - */ -OperatorNode.prototype.find = function (filter) { - var nodes = []; - - // check itself - if (this.match(filter)) { - nodes.push(this); - } - - // search in parameters - var params = this.params; - if (params) { - for (var i = 0, len = params.length; i < len; i++) { - nodes = nodes.concat(params[i].find(filter)); - } - } - - return nodes; -}; - -/** - * Get string representation - * @return {String} str - */ -OperatorNode.prototype.toString = function() { - var params = this.params; - - // special case: unary minus - if (this.fn === math.unary) { - return '-' + params[0].toString(); - } - - switch (params.length) { - case 1: // for example '5!' - return params[0].toString() + this.name; - - case 2: // for example '2+3' - var lhs = params[0].toString(); - if (params[0] instanceof OperatorNode) { - lhs = '(' + lhs + ')'; - } - var rhs = params[1].toString(); - if (params[1] instanceof OperatorNode) { - rhs = '(' + rhs + ')'; - } - return lhs + ' ' + this.name + ' ' + rhs; - - default: // this should occur. format as a function call - return this.name + '(' + this.params.join(', ') + ')'; - } -}; - -/** - * @constructor SymbolNode - * A symbol node can hold and resolve a symbol - * @param {String} name - * @param {math.expr.Scope} scope - * @extends {Node} - */ -function SymbolNode(name, scope) { - this.name = name; - this.scope = scope; -} - -SymbolNode.prototype = new Node(); - -math.expr.node.SymbolNode = SymbolNode; - -/** - * Evaluate the symbol. Throws an error when the symbol is undefined. - * @return {*} result - * @override - */ -SymbolNode.prototype.eval = function() { - // return the value of the symbol - var value = this.scope.get(this.name); - - if (value === undefined) { - throw new Error('Undefined symbol ' + this.name); - } - - return value; -}; - -/** - * Get string representation - * @return {String} str - * @override - */ -SymbolNode.prototype.toString = function() { - return this.name; -}; - -/** - * @constructor ParamsNode - * invoke a list with parameters on the results of a node - * @param {Node} object - * @param {Node[]} params - * @param {Scope[]} paramScopes A scope for every parameter, where the - * index variable 'end' can be defined. - */ -function ParamsNode (object, params, paramScopes) { - this.object = object; - this.params = params; - this.paramScopes = paramScopes; - - // check whether any of the params expressions uses the context symbol 'end' - this.hasContextParams = false; - if (params) { - var filter = { - type: math.type.SymbolNode, - properties: { - name: 'end' - } - }; - - for (var i = 0, len = params.length; i < len; i++) { - if (params[i].find(filter).length > 0) { - this.hasContextParams = true; - break; - } - } - } -} - -ParamsNode.prototype = new Node(); - -math.expr.node.ParamsNode = ParamsNode; - -/** - * Evaluate the parameters - * @return {*} result - */ -ParamsNode.prototype.eval = function() { - var i, len; - - // evaluate the object - var object = this.object; - if (object == undefined) { - throw new Error ('Node undefined'); - } - var obj = object.eval(); - - // evaluate the values of context parameter 'end' when needed - if (this.hasContextParams) { - var paramScopes = this.paramScopes, - size; - if (obj.size) { - size = obj.size(); // matrix - } - else if (obj.length !== undefined) { - size = [obj.length]; // string - } - else { - size = []; // scalar - } - - if (paramScopes && size) { - for (i = 0, len = this.params.length; i < len; i++) { - var paramScope = paramScopes[i]; - if (paramScope) { - paramScope.set('end', size[i] - 1); // zero-based end - } - } - } - } - - // evaluate the parameters - var params = this.params, - results = []; - for (i = 0, len = this.params.length; i < len; i++) { - results[i] = params[i].eval(); - } - - if (typeof obj === 'function') { - // invoke a function with the parameters - return obj.apply(this, results); - } - else { - // get a subset of the object - return math.subset(obj, results); - } -}; - -/** - * Find all nodes matching given filter - * @param {Object} filter See Node.find for a description of the filter options - * @returns {Node[]} nodes - */ -ParamsNode.prototype.find = function (filter) { - var nodes = []; - - // check itself - if (this.match(filter)) { - nodes.push(this); - } - - // search object - if (this.object) { - nodes = nodes.concat(this.object.find(filter)); - } - - // search in parameters - var params = this.params; - if (params) { - for (var i = 0, len = params.length; i < len; i++) { - nodes = nodes.concat(params[i].find(filter)); - } - } - - return nodes; -}; - -/** - * Get string representation - * @return {String} str - */ -ParamsNode.prototype.toString = function() { - // format the parameters like "(2, 4.2)" - var str = this.object ? this.object.toString() : ''; - if (this.params) { - str += '(' + this.params.join(', ') + ')'; - } - return str; -}; - -/** - * @constructor MatrixNode - * Holds an 2-dimensional array with nodes - * @param {Array[]} nodes 2 dimensional array with nodes - * @extends {Node} - */ -function MatrixNode(nodes) { - this.nodes = nodes || []; -} - -MatrixNode.prototype = new Node(); - -math.expr.node.MatrixNode = MatrixNode; - -(function () { - /** - * Evaluate the array - * @return {Matrix} results - * @override - */ - MatrixNode.prototype.eval = function() { - // evaluate all nodes in the 2d array, and merge the results into a matrix - var nodes = this.nodes, - results = [], - mergeNeeded = false; - - for (var r = 0, rows = nodes.length; r < rows; r++) { - var nodes_r = nodes[r]; - var results_r = []; - for (var c = 0, cols = nodes_r.length; c < cols; c++) { - var results_rc = nodes_r[c].eval(); - if (results_rc instanceof Matrix || - results_rc instanceof Range || - Array.isArray(results_rc)) { - mergeNeeded = true; - } - results_r[c] = results_rc; - } - results[r] = results_r; - } - - if (mergeNeeded) { - results = merge(results); - } - - return new Matrix(results); - }; - - /** - * Find all nodes matching given filter - * @param {Object} filter See Node.find for a description of the filter options - * @returns {Node[]} nodes - */ - MatrixNode.prototype.find = function (filter) { - var results = []; - - // check itself - if (this.match(filter)) { - results.push(this); - } - - // search in all nodes - var nodes = this.nodes; - for (var r = 0, rows = nodes.length; r < rows; r++) { - var nodes_r = nodes[r]; - for (var c = 0, cols = nodes_r.length; c < cols; c++) { - results = results.concat(nodes_r[c].find(filter)); - } - } - - return results; - }; - - /** - * Merge nested Matrices in a two dimensional Array. - * @param {Array} array Two-dimensional array containing Matrices - * @return {Array} merged The merged array (two-dimensional) - */ - function merge (array) { - var merged = []; - var rows = array.length; - for (var r = 0; r < rows; r++) { - var array_r = array[r]; - var cols = array_r.length; - var submatrix = null; - var submatrixRows = null; - for (var c = 0; c < cols; c++) { - var entry = math.clone(array_r[c]); - var size; - if (entry instanceof Matrix) { - // get the data from the matrix - size = entry.size(); - entry = entry.valueOf(); - if (size.length == 1) { - entry = [entry]; - size = [1, size[0]]; - } - else if (size.length > 2) { - throw new Error('Cannot merge a multi dimensional matrix'); - } - } - else if (entry instanceof Range) { - // change range into an 1xn matrix - entry = [entry.valueOf()]; - size = [1, entry[0].length]; - } - else if (Array.isArray(entry)) { - // change array into a 1xn matrix - size = [1, entry.length]; - entry = [entry]; - } - else { - // change scalar into a 1x1 matrix - size = [1, 1]; - entry = [[entry]]; - } - - // check the height of this row - if (submatrix == null) { - // first entry - submatrix = entry; - submatrixRows = size[0]; - } - else if (size[0] == submatrixRows) { - // merge - for (var s = 0; s < submatrixRows; s++) { - submatrix[s] = submatrix[s].concat(entry[s]); - } - } - else { - // no good... - throw new Error('Dimension mismatch ' + - '(' + size[0] + ' != ' + submatrixRows + ')'); - } - } - - // merge the submatrix - merged = merged.concat(submatrix); - } - - return merged; - } - - /** - * Get string representation - * @return {String} str - * @override - */ - MatrixNode.prototype.toString = function() { - return util.formatArray(this.nodes); - }; -})(); -/** - * @constructor BlockNode - * Holds a set with nodes - * @extends {Node} - */ -function BlockNode() { - this.params = []; - this.visible = []; -} - -BlockNode.prototype = new Node(); - -math.expr.node.BlockNode = BlockNode; - -/** - * Add a parameter - * @param {Node} param - * @param {Boolean} [visible] true by default - */ -BlockNode.prototype.add = function (param, visible) { - var index = this.params.length; - this.params[index] = param; - this.visible[index] = (visible != undefined) ? visible : true; -}; - -/** - * Evaluate the set - * @return {*[]} results - * @override - */ -BlockNode.prototype.eval = function() { - // evaluate the parameters - var results = []; - for (var i = 0, iMax = this.params.length; i < iMax; i++) { - var result = this.params[i].eval(); - if (this.visible[i]) { - results.push(result); - } - } - - return results; -}; - -/** - * Find all nodes matching given filter - * @param {Object} filter See Node.find for a description of the filter options - * @returns {Node[]} nodes - */ -BlockNode.prototype.find = function (filter) { - var nodes = []; - - // check itself - if (this.match(filter)) { - nodes.push(this); - } - - // search in parameters - var params = this.params; - if (params) { - for (var i = 0, len = params.length; i < len; i++) { - nodes = nodes.concat(params[i].find(filter)); - } - } - - return nodes; -}; - -/** - * Get string representation - * @return {String} str - * @override - */ -BlockNode.prototype.toString = function() { - var strings = []; - - for (var i = 0, iMax = this.params.length; i < iMax; i++) { - if (this.visible[i]) { - strings.push('\n ' + this.params[i].toString()); - } - } - - return '[' + strings.join(',') + '\n]'; -}; - -/** - * @constructor AssignmentNode - * Define a symbol, like "a = 3.2" - * - * @param {String} name Symbol name - * @param {Node} expr The expression defining the symbol - * @param {math.expr.Scope} scope Scope to store the result - */ -function AssignmentNode(name, expr, scope) { - this.name = name; - this.expr = expr; - this.scope = scope; -} - -AssignmentNode.prototype = new Node(); - -math.expr.node.AssignmentNode = AssignmentNode; - -/** - * Evaluate the assignment - * @return {*} result - */ -AssignmentNode.prototype.eval = function() { - if (this.expr === undefined) { - throw new Error('Undefined symbol ' + this.name); - } - - var result = this.expr.eval(); - this.scope.set(this.name, result); - - return result; -}; - -/** - * Find all nodes matching given filter - * @param {Object} filter See Node.find for a description of the filter options - * @returns {Node[]} nodes - */ -AssignmentNode.prototype.find = function (filter) { - var nodes = []; - - // check itself - if (this.match(filter)) { - nodes.push(this); - } - - // search in expression - if (this.expr) { - nodes = nodes.concat(this.expr.find(filter)); - } - - return nodes; -}; - -/** - * Get string representation - * @return {String} - */ -AssignmentNode.prototype.toString = function() { - return this.name + ' = ' + this.expr.toString(); -}; - -/** - * @constructor UpdateNode - * Update a symbol value, like a(2,3) = 4.5 - * - * @param {String} name Symbol name - * @param {Node[] | undefined} params One or more parameters - * @param {Scope[]} paramScopes A scope for every parameter, where the - * index variable 'end' can be defined. - * @param {Node} expr The expression defining the symbol - * @param {math.expr.Scope} scope Scope to store the result - */ -function UpdateNode(name, params, paramScopes, expr, scope) { - this.name = name; - this.params = params; - this.paramScopes = paramScopes; - this.expr = expr; - this.scope = scope; - - // check whether any of the params expressions uses the context symbol 'end' - this.hasContextParams = false; - var filter = { - type: math.type.SymbolNode, - properties: { - name: 'end' - } - }; - for (var i = 0, len = params.length; i < len; i++) { - if (params[i].find(filter).length > 0) { - this.hasContextParams = true; - break; - } - } -} - -UpdateNode.prototype = new Node(); - -math.expr.node.UpdateNode = UpdateNode; - -/** - * Evaluate the assignment - * @return {*} result - */ -UpdateNode.prototype.eval = function() { - if (this.expr === undefined) { - throw new Error('Undefined symbol ' + this.name); - } - - var result; - var params = this.params; - - // test if definition is currently undefined - var prevResult = this.scope.get(this.name); - if (prevResult == undefined) { - throw new Error('Undefined symbol ' + this.name); - } - - // evaluate the values of context parameter 'end' when needed - if (this.hasContextParams) { - var paramScopes = this.paramScopes, - size; - if (prevResult.size) { - size = prevResult.size(); // matrix - } - else if (prevResult.length !== undefined) { - size = [prevResult.length]; // string - } - else { - size = []; // scalar - } - - if (paramScopes && size) { - for (var i = 0, len = this.params.length; i < len; i++) { - var paramScope = paramScopes[i]; - if (paramScope) { - paramScope.set('end', size[i] - 1); - } - } - } - } - - // change part of a matrix, for example "a=[]", "a(2,3)=4.5" - var paramResults = []; - this.params.forEach(function (param) { - paramResults.push(param.eval()); - }); - - var exprResult = this.expr.eval(); - - // replace subset - result = math.subset(prevResult, paramResults, exprResult); - - this.scope.set(this.name, result); - - return result; -}; - -/** - * Find all nodes matching given filter - * @param {Object} filter See Node.find for a description of the filter options - * @returns {Node[]} nodes - */ -UpdateNode.prototype.find = function (filter) { - var nodes = []; - - // check itself - if (this.match(filter)) { - nodes.push(this); - } - - // search in parameters - var params = this.params; - if (params) { - for (var i = 0, len = params.length; i < len; i++) { - nodes = nodes.concat(params[i].find(filter)); - } - } - - // search in expression - if (this.expr) { - nodes = nodes.concat(this.expr.find(filter)); - } - - return nodes; -}; - -/** - * Get string representation - * @return {String} - */ -UpdateNode.prototype.toString = function() { - var str = ''; - - str += this.name; - if (this.params && this.params.length) { - str += '(' + this.params.join(', ') + ')'; - } - str += ' = '; - str += this.expr.toString(); - - return str; -}; - -/** - * @constructor FunctionNode - * Function assignment - * - * @param {String} name Function name - * @param {String[]} variables Variable names - * @param {Node} expr The function expression - * @param {math.expr.Scope} functionScope Scope in which to write variable - * values - * @param {math.expr.Scope} scope Scope to store the resulting - * function assignment - */ -function FunctionNode(name, variables, expr, functionScope, scope) { - this.name = name; - this.variables = variables; - this.expr = expr; - this.scope = scope; - - // create function - this.fn = function () { - var num = variables ? variables.length : 0; - - // validate correct number of arguments - if (arguments.length != num) { - throw newArgumentsError(name, arguments.length, num); - } - - // fill in the provided arguments in the functionScope variables - for (var i = 0; i < num; i++) { - functionScope.set(variables[i], arguments[i]); - } - - // evaluate the expression - return expr.eval(); - }; - - this.fn.toString = function() { - // TODO: what to return as toString? - return name + '(' + variables.join(', ') + ')'; - //return name + '(' + variableNames.join(', ') + ') = ' + expr.toString(); - }; -} - -FunctionNode.prototype = new Node(); - -math.expr.node.FunctionNode = FunctionNode; - -/** - * Evaluate the function assignment - * @return {function} fn - */ -FunctionNode.prototype.eval = function() { - // put the definition in the scope - this.scope.set(this.name, this.fn); - - return this.fn; -}; - -/** - * Find all nodes matching given filter - * @param {Object} filter See Node.find for a description of the filter options - * @returns {Node[]} nodes - */ -FunctionNode.prototype.find = function (filter) { - var nodes = []; - - // check itself - if (this.match(filter)) { - nodes.push(this); - } - - // search in expression - if (this.expr) { - nodes = nodes.concat(this.expr.find(filter)); - } - - return nodes; -}; - -/** - * get string representation - * @return {String} str - */ -FunctionNode.prototype.toString = function() { - return this.fn.toString(); -}; - - -/** - * Scope - * A scope stores values of symbols: variables and functions. - * - * Syntax: - * var scope = new math.expr.Scope(); - * var scope = new math.expr.Scope(parentScope); - * var scope = new math.expr.Scope(symbols); - * var scope = new math.expr.Scope(parentScope, symbols); - * - * Where: - * {math.expr.Scope} parentScope Scope will be linked to a parent scope, - * which is traversed when resolving - * symbols. - * {Object} symbols A custom object that will be used to - * resolve and store variables. - * - * @constructor math.expr.Scope - * @param {...} [args] - */ -math.expr.Scope = function Scope(args) { - /** @type {math.expr.Scope} */ - this.parentScope = null; - // TODO: rename parentScope to previousScope, add a nextScope, change Scope to a linked list node - - /** @type {math.expr.Scope[]} */ - this.subScopes = null; - // TODO: rename subScopes to childScopes (or childNodes?) - - /** @type {Object.} */ - this.symbols = {}; // variables and functions - - /** @type {Object.} */ - this.cache = {}; // cache, referring to the scope.symbols object where - // a variable was last found - - // read first argument (can be parentScope or symbols map) - if (arguments.length > 0) { - var arg0 = arguments[0]; - if (arg0 instanceof math.expr.Scope) { - this.parentScope = arg0; - } - else if (arg0 instanceof Object) { - this.symbols = arg0; - } - } - - // read second argument (can be symbols map) - if (arguments.length > 1) { - var arg1 = arguments[1]; - if (arg1 instanceof Object) { - this.symbols = arg1; - } - } -}; - -math.expr.Scope.prototype = { - /** - * Create a sub scope - * The variables in a sub scope are not accessible from the parent scope - * @return {math.expr.Scope} subScope - */ - createSubScope: function () { - var subScope = new math.expr.Scope(this); - if (!this.subScopes) { - this.subScopes = []; - } - this.subScopes.push(subScope); - return subScope; - }, - - /** - * Get a symbol value by name. - * Returns undefined if the symbol is not found in this scope or any of - * its parent scopes. - * @param {String} name - * @returns {* | undefined} value - */ - get: function (name) { - var value; - - // check itself - value = this.symbols[name]; - if (value !== undefined) { - return value; - } - - // read from cache - var symbols = this.cache[name]; - if (symbols) { - return symbols[name]; - } - - // check parent scope - var parent = this.parentScope; - while (parent) { - value = parent.symbols[name]; - if (value !== undefined) { - this.cache[name] = parent.symbols; - return value; - } - parent = parent.parentScope; - } - - // check math namespace - value = math[name]; - if (value !== undefined) { - this.cache[name] = math; - return value; - } - - // check if name is a unit - if (Unit.isPlainUnit(name)) { - value = new Unit(null, name); - this.cache[name] = {}; - this.cache[name][name] = value; - return value; - } - - return undefined; - }, - - /** - * Test whether this scope contains a symbol (will not check parent scopes) - * @param {String} name - * @return {Boolean} hasSymbol - */ - has: function (name) { - return (this.symbols[name] !== undefined); - }, - - /** - * Set a symbol value - * @param {String} name - * @param {*} value - * @return {*} value - */ - set: function (name, value) { - return this.symbols[name] = value; - }, - - /** - * Remove a symbol by name - * @param {String} name - */ - remove: function(name) { - delete this.symbols[name]; - }, - - /** - * Clear all symbols in this scope, its sub scopes, and clear the cache. - * Parent scopes will not be cleared. - */ - clear: function () { - var symbols = this.symbols; - for (var name in symbols) { - if (symbols.hasOwnProperty(name)) { - delete symbols[name]; - } - } - - if (this.subScopes) { - var subScopes = this.subScopes; - for (var i = 0, iMax = subScopes.length; i < iMax; i++) { - subScopes[i].clear(); - } - } - - this.clearCache(); - }, - - /** - * Clear cached links to symbols in other scopes - */ - clearCache: function () { - this.cache = {}; - } -}; - - -/** - * @constructor math.expr.Parser - * Parser contains methods to evaluate or parse expressions, and has a number - * of convenience methods to get, set, and remove variables from memory. Parser - * keeps a scope containing variables in memory, which is used for all - * evaluations. - * - * Methods: - * var result = parser.eval(expr); // evaluate an expression - * var value = parser.get(name); // retrieve a variable from the parser - * parser.set(name, value); // set a variable in the parser - * parser.remove(name); // clear a variable from the - * // parsers scope - * parser.clear(); // clear the parsers scope - * - * // it is possible to parse an expression into a node tree: - * var node = parser.parse(expr); // parse an expression into a node tree - * var result = node.eval(); // evaluate a parsed node - * - * Example usage: - * var parser = new math.expr.Parser(); - * // Note: there is a convenience method which can be used instead: - * // var parser = new math.parser(); - * - * // evaluate expressions - * parser.eval('sqrt(3^2 + 4^2)'); // 5 - * parser.eval('sqrt(-4)'); // 2i - * parser.eval('2 inch in cm'); // 5.08 cm - * parser.eval('cos(45 deg)'); // 0.7071067811865476 - * - * // define variables and functions - * parser.eval('x = 7 / 2'); // 3.5 - * parser.eval('x + 3'); // 6.5 - * parser.eval('function f(x, y) = x^y'); // f(x, y) - * parser.eval('f(2, 3)'); // 8 - * - * // get and set variables and functions - * var x = parser.get('x'); // 7 - * var f = parser.get('f'); // function - * var g = f(3, 2); // 9 - * parser.set('h', 500); - * var i = parser.eval('h / 2'); // 250 - * parser.set('hello', function (name) { - * return 'hello, ' + name + '!'; - * }); - * parser.eval('hello("user")'); // "hello, user!" - * - * // clear defined functions and variables - * parser.clear(); - */ -math.expr.Parser = function Parser() { - if (!(this instanceof math.expr.Parser)) { - throw new SyntaxError( - 'Parser constructor must be called with the new operator'); - } - - this.scope = new math.expr.Scope(); -}; - -/** - * Parse an expression end return the parsed function node. - * The node can be evaluated via node.eval() - * @param {String} expr - * @return {Node} node - * @throws {Error} - */ -math.expr.Parser.prototype.parse = function (expr) { - return math.parse(expr, this.scope); -}; - -/** - * Parse and evaluate the given expression - * @param {String} expr A string containing an expression, for example "2+3" - * @return {*} result The result, or undefined when the expression was empty - * @throws {Error} - */ -math.expr.Parser.prototype.eval = function (expr) { - var node = math.parse(expr, this.scope); - return node.eval(); -}; - -/** - * Get a variable (a function or variable) by name from the parsers scope. - * Returns undefined when not found - * @param {String} name - * @return {* | undefined} value - */ -math.expr.Parser.prototype.get = function (name) { - return this.scope.get(name); -}; - -/** - * Set a symbol (a function or variable) by name from the parsers scope. - * @param {String} name - * @param {* | undefined} value - */ -math.expr.Parser.prototype.set = function (name, value) { - this.scope.set(name, value); -}; - -/** - * Remove a variable from the parsers scope - * @param {String} name - */ -math.expr.Parser.prototype.remove = function (name) { - this.scope.remove(name); -}; - -/** - * Clear the scope with variables and functions - */ -math.expr.Parser.prototype.clear = function () { - this.scope.clear(); -}; - -/** - * Calculate the absolute value of a value. - * - * abs(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ -math.abs = function abs(x) { - if (arguments.length != 1) { - throw newArgumentsError('abs', arguments.length, 1); - } - - if (isNumber(x)) { - return Math.abs(x); - } - - if (x instanceof Complex) { - return Math.sqrt(x.re * x.re + x.im * x.im); - } - - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.abs); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.abs(x.valueOf()); - } - - throw newUnsupportedTypeError('abs', x); -}; - -/** - * Add two values - * - * x + y - * add(x, y) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Unit | String | Array | Matrix} x - * @param {Number | Complex | Unit | String | Array | Matrix} y - * @return {Number | Complex | Unit | String | Array | Matrix} res - */ -math.add = function add(x, y) { - if (arguments.length != 2) { - throw newArgumentsError('add', arguments.length, 2); - } - - if (isNumber(x)) { - if (isNumber(y)) { - // number + number - return x + y; - } - else if (y instanceof Complex) { - // number + complex - return Complex.create( - x + y.re, - y.im - ) - } - } - else if (x instanceof Complex) { - if (isNumber(y)) { - // complex + number - return Complex.create( - x.re + y, - x.im - ) - } - else if (y instanceof Complex) { - // complex + complex - return Complex.create( - x.re + y.re, - x.im + y.im - ); - } - } - else if (x instanceof Unit) { - if (y instanceof Unit) { - if (!x.equalBase(y)) { - throw new Error('Units do not match'); - } - - if (x.value == null) { - throw new Error('Unit on left hand side of operator + has an undefined value'); - } - - if (y.value == null) { - throw new Error('Unit on right hand side of operator + has an undefined value'); - } - - var res = x.clone(); - res.value += y.value; - res.fixPrefix = false; - return res; - } - } - - if (isString(x) || isString(y)) { - return x + y; - } - - if (Array.isArray(x) || x instanceof Matrix || - Array.isArray(y) || y instanceof Matrix) { - return util.map2(x, y, math.add); - } - - if (x.valueOf() !== x || y.valueOf() !== y) { - // fallback on the objects primitive value - return math.add(x.valueOf(), y.valueOf()); - } - - throw newUnsupportedTypeError('add', x, y); -}; - -/** - * Round a value towards plus infinity - * - * ceil(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ -math.ceil = function ceil(x) { - if (arguments.length != 1) { - throw newArgumentsError('ceil', arguments.length, 1); - } - - if (isNumber(x)) { - return Math.ceil(x); - } - - if (x instanceof Complex) { - return Complex.create ( - Math.ceil(x.re), - Math.ceil(x.im) - ); - } - - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.ceil); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.ceil(x.valueOf()); - } - - throw newUnsupportedTypeError('ceil', x); -}; - -/** - * Compute the cube of a value - * - * x .* x .* x - * cube(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ -math.cube = function cube(x) { - if (arguments.length != 1) { - throw newArgumentsError('cube', arguments.length, 1); - } - - if (isNumber(x)) { - return x * x * x; - } - - if (x instanceof Complex) { - return math.multiply(math.multiply(x, x), x); - } - - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.cube); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.cube(x.valueOf()); - } - - throw newUnsupportedTypeError('cube', x); -}; - -/** - * Divide two values. - * - * x / y - * divide(x, y) - * - * @param {Number | Complex | Unit | Array | Matrix} x - * @param {Number | Complex} y - * @return {Number | Complex | Unit | Array | Matrix} res - */ -math.divide = function divide(x, y) { - if (arguments.length != 2) { - throw newArgumentsError('divide', arguments.length, 2); - } - - if (isNumber(x)) { - if (isNumber(y)) { - // number / number - return x / y; - } - else if (y instanceof Complex) { - // number / complex - return _divideComplex(new Complex(x, 0), y); - } - } - - if (x instanceof Complex) { - if (isNumber(y)) { - // complex / number - return _divideComplex(x, new Complex(y, 0)); - } - else if (y instanceof Complex) { - // complex / complex - return _divideComplex(x, y); - } - } - - if (x instanceof Unit) { - if (isNumber(y)) { - var res = x.clone(); - res.value /= y; - return res; - } - } - - if (Array.isArray(x) || x instanceof Matrix) { - if (Array.isArray(y) || y instanceof Matrix) { - // TODO: implement matrix right division using pseudo inverse - // http://www.mathworks.nl/help/matlab/ref/mrdivide.html - // http://www.gnu.org/software/octave/doc/interpreter/Arithmetic-Ops.html - // http://stackoverflow.com/questions/12263932/how-does-gnu-octave-matrix-division-work-getting-unexpected-behaviour - return math.multiply(x, math.inv(y)); - } - else { - // matrix / scalar - return util.map2(x, y, math.divide); - } - } - - if (Array.isArray(y) || y instanceof Matrix) { - // TODO: implement matrix right division using pseudo inverse - return math.multiply(x, math.inv(y)); - } - - if (x.valueOf() !== x || y.valueOf() !== y) { - // fallback on the objects primitive value - return math.divide(x.valueOf(), y.valueOf()); - } - - throw newUnsupportedTypeError('divide', x, y); -}; - -/** - * Divide two complex numbers. x / y or divide(x, y) - * @param {Complex} x - * @param {Complex} y - * @return {Complex} res - * @private - */ -function _divideComplex (x, y) { - var den = y.re * y.re + y.im * y.im; - if (den != 0) { - return Complex.create( - (x.re * y.re + x.im * y.im) / den, - (x.im * y.re - x.re * y.im) / den - ); - } - else { - // both y.re and y.im are zero - return Complex.create( - (x.re != 0) ? (x.re / 0) : 0, - (x.im != 0) ? (x.im / 0) : 0 - ); - } -} - -/** - * Divide two values element wise. - * - * x ./ y - * edivide(x, y) - * - * @param {Number | Complex | Unit | Array | Matrix} x - * @param {Number | Complex | Unit | Array | Matrix} y - * @return {Number | Complex | Unit | Array | Matrix} res - */ -math.edivide = function edivide(x, y) { - if (arguments.length != 2) { - throw newArgumentsError('edivide', arguments.length, 2); - } - - return util.deepMap2(x, y, math.divide); -}; - -/** - * Multiply two values element wise. - * - * x .* y - * emultiply(x, y) - * - * @param {Number | Complex | Unit | Array | Matrix} x - * @param {Number | Complex | Unit | Array | Matrix} y - * @return {Number | Complex | Unit | Array | Matrix} res - */ -math.emultiply = function emultiply(x, y) { - if (arguments.length != 2) { - throw newArgumentsError('emultiply', arguments.length, 2); - } - - return util.deepMap2(x, y, math.multiply); -}; - -/** - * Calculates the power of x to y element wise - * - * x .^ y - * epow(x, y) - * - * @param {Number | Complex | Unit | Array | Matrix} x - * @param {Number | Complex | Unit | Array | Matrix} y - * @return {Number | Complex | Unit | Array | Matrix} res - */ -math.epow = function epow(x, y) { - if (arguments.length != 2) { - throw newArgumentsError('epow', arguments.length, 2); - } - - return util.deepMap2(x, y, math.pow); -}; - -/** - * Check if value x equals y, - * - * x == y - * equal(x, y) - * - * For matrices, the function is evaluated element wise. - * In case of complex numbers, x.re must equal y.re, and x.im must equal y.im. - * - * @param {Number | Complex | Unit | String | Array | Matrix} x - * @param {Number | Complex | Unit | String | Array | Matrix} y - * @return {Boolean | Array | Matrix} res - */ -math.equal = function equal(x, y) { - if (arguments.length != 2) { - throw newArgumentsError('equal', arguments.length, 2); - } - - if (isNumber(x)) { - if (isNumber(y)) { - return x == y; - } - else if (y instanceof Complex) { - return (x == y.re) && (y.im == 0); - } - } - if (x instanceof Complex) { - if (isNumber(y)) { - return (x.re == y) && (x.im == 0); - } - else if (y instanceof Complex) { - return (x.re == y.re) && (x.im == y.im); - } - } - - if ((x instanceof Unit) && (y instanceof Unit)) { - if (!x.equalBase(y)) { - throw new Error('Cannot compare units with different base'); - } - return x.value == y.value; - } - - if (isString(x) || isString(y)) { - return x == y; - } - - if (Array.isArray(x) || x instanceof Matrix || - Array.isArray(y) || y instanceof Matrix) { - return util.map2(x, y, math.equal); - } - - if (x.valueOf() !== x || y.valueOf() !== y) { - // fallback on the objects primitive values - return equal(x.valueOf(), y.valueOf()); - } - - throw newUnsupportedTypeError('equal', x, y); -}; - -/** - * Calculate the exponent of a value - * - * exp(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ -math.exp = function exp (x) { - if (arguments.length != 1) { - throw newArgumentsError('exp', arguments.length, 1); - } - - if (isNumber(x)) { - return Math.exp(x); - } - if (x instanceof Complex) { - var r = Math.exp(x.re); - return Complex.create( - r * Math.cos(x.im), - r * Math.sin(x.im) - ); - } - - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.exp); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.exp(x.valueOf()); - } - - throw newUnsupportedTypeError('exp', x); -}; - -/** - * Round a value towards zero - * - * fix(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ -math.fix = function fix(x) { - if (arguments.length != 1) { - throw newArgumentsError('fix', arguments.length, 1); - } - - if (isNumber(x)) { - return (x > 0) ? Math.floor(x) : Math.ceil(x); - } - - if (x instanceof Complex) { - return Complex.create( - (x.re > 0) ? Math.floor(x.re) : Math.ceil(x.re), - (x.im > 0) ? Math.floor(x.im) : Math.ceil(x.im) - ); - } - - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.fix); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.fix(x.valueOf()); - } - - throw newUnsupportedTypeError('fix', x); -}; - -/** - * Round a value towards minus infinity - * - * floor(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ -math.floor = function floor(x) { - if (arguments.length != 1) { - throw newArgumentsError('floor', arguments.length, 1); - } - - if (isNumber(x)) { - return Math.floor(x); - } - - if (x instanceof Complex) { - return Complex.create ( - Math.floor(x.re), - Math.floor(x.im) - ); - } - - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.floor); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.floor(x.valueOf()); - } - - throw newUnsupportedTypeError('floor', x); -}; - -/** - * Calculate the greatest common divisor for two or more values or arrays. - * - * gcd(a, b) - * gcd(a, b, c, ...) - * - * For matrices, the function is evaluated element wise. - * - * @param {... Number | Array | Matrix} args two or more integer numbers - * @return {Number | Array | Matrix} greatest common divisor - */ -math.gcd = function gcd(args) { - var a = arguments[0], - b = arguments[1], - t; - - if (arguments.length == 2) { - // two arguments - if (isNumber(a) && isNumber(b)) { - if (!isInteger(a) || !isInteger(b)) { - throw new Error('Parameters in function gcd must be integer numbers'); - } - - // http://en.wikipedia.org/wiki/Euclidean_algorithm - while (b != 0) { - t = b; - b = a % t; - a = t; - } - return Math.abs(a); - } - - // evaluate gcd element wise - if (Array.isArray(a) || a instanceof Matrix || - Array.isArray(b) || b instanceof Matrix) { - return util.map2(a, b, math.gcd); - } - - if (a.valueOf() !== a || b.valueOf() !== b) { - // fallback on the objects primitive value - return math.gcd(a.valueOf(), b.valueOf()); - } - - throw newUnsupportedTypeError('gcd', a, b); - } - - if (arguments.length > 2) { - // multiple arguments. Evaluate them iteratively - for (var i = 1; i < arguments.length; i++) { - a = math.gcd(a, arguments[i]); - } - return a; - } - - // zero or one argument - throw new SyntaxError('Function gcd expects two or more arguments'); -}; - -/** - * Check if value x is larger y - * - * x > y - * larger(x, y) - * - * For matrices, the function is evaluated element wise. - * In case of complex numbers, the absolute values of a and b are compared. - * - * @param {Number | Complex | Unit | String | Array | Matrix} x - * @param {Number | Complex | Unit | String | Array | Matrix} y - * @return {Boolean | Array | Matrix} res - */ -math.larger = function larger(x, y) { - if (arguments.length != 2) { - throw newArgumentsError('larger', arguments.length, 2); - } - - if (isNumber(x)) { - if (isNumber(y)) { - return x > y; - } - else if (y instanceof Complex) { - return x > math.abs(y); - } - } - if (x instanceof Complex) { - if (isNumber(y)) { - return math.abs(x) > y; - } - else if (y instanceof Complex) { - return math.abs(x) > math.abs(y); - } - } - - if ((x instanceof Unit) && (y instanceof Unit)) { - if (!x.equalBase(y)) { - throw new Error('Cannot compare units with different base'); - } - return x.value > y.value; - } - - if (isString(x) || isString(y)) { - return x > y; - } - - if (Array.isArray(x) || x instanceof Matrix || - Array.isArray(y) || y instanceof Matrix) { - return util.map2(x, y, math.larger); - } - - if (x.valueOf() !== x || y.valueOf() !== y) { - // fallback on the objects primitive values - return math.larger(x.valueOf(), y.valueOf()); - } - - throw newUnsupportedTypeError('larger', x, y); -}; - -/** - * Check if value x is larger or equal to y - * - * x >= y - * largereq(x, y) - * - * For matrices, the function is evaluated element wise. - * In case of complex numbers, the absolute values of a and b are compared. - * - * @param {Number | Complex | Unit | String | Array | Matrix} x - * @param {Number | Complex | Unit | String | Array | Matrix} y - * @return {Boolean | Array | Matrix} res - */ -math.largereq = function largereq(x, y) { - if (arguments.length != 2) { - throw newArgumentsError('largereq', arguments.length, 2); - } - - if (isNumber(x)) { - if (isNumber(y)) { - return x >= y; - } - else if (y instanceof Complex) { - return x >= math.abs(y); - } - } - if (x instanceof Complex) { - if (isNumber(y)) { - return math.abs(x) >= y; - } - else if (y instanceof Complex) { - return math.abs(x) >= math.abs(y); - } - } - - if ((x instanceof Unit) && (y instanceof Unit)) { - if (!x.equalBase(y)) { - throw new Error('Cannot compare units with different base'); - } - return x.value >= y.value; - } - - if (isString(x) || isString(y)) { - return x >= y; - } - - if (Array.isArray(x) || x instanceof Matrix || - Array.isArray(y) || y instanceof Matrix) { - return util.map2(x, y, math.largereq); - } - - if (x.valueOf() !== x || y.valueOf() !== y) { - // fallback on the objects primitive values - return math.largereq(x.valueOf(), y.valueOf()); - } - - throw newUnsupportedTypeError('largereq', x, y); -}; - -/** - * Calculate the least common multiple for two or more values or arrays. - * - * lcm(a, b) - * lcm(a, b, c, ...) - * - * lcm is defined as: - * lcm(a, b) = abs(a * b) / gcd(a, b) - * - * For matrices, the function is evaluated element wise. - * - * @param {... Number | Array | Matrix} args two or more integer numbers - * @return {Number | Array | Matrix} least common multiple - */ -math.lcm = function lcm(args) { - var a = arguments[0], - b = arguments[1], - t; - - if (arguments.length == 2) { - // two arguments - if (isNumber(a) && isNumber(b)) { - if (!isInteger(a) || !isInteger(b)) { - throw new Error('Parameters in function lcm must be integer numbers'); - } - - // http://en.wikipedia.org/wiki/Euclidean_algorithm - // evaluate gcd here inline to reduce overhead - var prod = a * b; - while (b != 0) { - t = b; - b = a % t; - a = t; - } - return Math.abs(prod / a); - } - - // evaluate lcm element wise - if (Array.isArray(a) || a instanceof Matrix || - Array.isArray(b) || b instanceof Matrix) { - return util.map2(a, b, math.lcm); - } - - if (a.valueOf() !== a || b.valueOf() !== b) { - // fallback on the objects primitive value - return math.lcm(a.valueOf(), b.valueOf()); - } - - throw newUnsupportedTypeError('lcm', a, b); - } - - if (arguments.length > 2) { - // multiple arguments. Evaluate them iteratively - for (var i = 1; i < arguments.length; i++) { - a = math.lcm(a, arguments[i]); - } - return a; - } - - // zero or one argument - throw new SyntaxError('Function lcm expects two or more arguments'); -}; - -/** - * Calculate the logarithm of a value - * - * log(x) - * log(x, base) - * - * base is optional. If not provided, the natural logarithm of x is calculated. - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @param {Number | Complex} [base] - * @return {Number | Complex | Array | Matrix} res - */ -math.log = function log(x, base) { - if (arguments.length == 1) { - // calculate natural logarithm, log(x) - if (isNumber(x)) { - if (x >= 0) { - return Math.log(x); - } - else { - // negative value -> complex value computation - return math.log(new Complex(x, 0)); - } - } - - if (x instanceof Complex) { - return Complex.create ( - Math.log(Math.sqrt(x.re * x.re + x.im * x.im)), - Math.atan2(x.im, x.re) - ); - } - - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.log); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive values - return math.log(x.valueOf()); - } - - throw newUnsupportedTypeError('log', x); - } - else if (arguments.length == 2) { - // calculate logarithm for a specified base, log(x, base) - return math.divide(math.log(x), math.log(base)); - } - else { - throw newArgumentsError('log', arguments.length, 1, 2); - } -}; - -/** - * Calculate the 10-base logarithm of a value - * - * log10(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ -math.log10 = function log10(x) { - if (arguments.length != 1) { - throw newArgumentsError('log10', arguments.length, 1); - } - - if (isNumber(x)) { - if (x >= 0) { - return Math.log(x) / Math.LN10; - } - else { - // negative value -> complex value computation - return math.log10(new Complex(x, 0)); - } - } - - if (x instanceof Complex) { - return Complex.create ( - Math.log(Math.sqrt(x.re * x.re + x.im * x.im)) / Math.LN10, - Math.atan2(x.im, x.re) / Math.LN10 - ); - } - - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.log10); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.log10(x.valueOf()); - } - - throw newUnsupportedTypeError('log10', x); -}; - -/** - * Calculates the modulus, the remainder of an integer division. - * - * x % y - * mod(x, y) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @param {Number | Complex | Array | Matrix} y - * @return {Number | Array | Matrix} res - */ -math.mod = function mod(x, y) { - if (arguments.length != 2) { - throw newArgumentsError('mod', arguments.length, 2); - } - - // see http://functions.wolfram.com/IntegerFunctions/Mod/ - - if (isNumber(x) && isNumber(y)) { - // number % number - return _mod(x, y); - } - - // TODO: implement mod for complex values - - if (Array.isArray(x) || x instanceof Matrix || - Array.isArray(y) || y instanceof Matrix) { - return util.map2(x, y, math.mod); - } - - if (x.valueOf() !== x || y.valueOf() !== y) { - // fallback on the objects primitive values - return math.mod(x.valueOf(), y.valueOf()); - } - - throw newUnsupportedTypeError('mod', x, y); -}; - -/** - * Calculate the modulus of two numbers - * @param {Number} x - * @param {Number} y - * @returns {number} res - * @private - */ -function _mod(x, y) { - if (y > 0) { - if (x > 0) { - return x % y; - } - else if (x == 0) { - return 0; - } - else { // x < 0 - return x - y * Math.floor(x / y); - } - } - else if (y == 0) { - return x; - } - else { // y < 0 - // TODO: implement mod for a negative divisor - throw new Error('Cannot calculate mod for a negative divisor'); - } -} -/** - * Multiply two values. - * - * x * y - * multiply(x, y) - * - * @param {Number | Complex | Unit | Array | Matrix} x - * @param {Number | Complex | Unit | Array | Matrix} y - * @return {Number | Complex | Unit | Array | Matrix} res - */ -math.multiply = function multiply(x, y) { - if (arguments.length != 2) { - throw newArgumentsError('multiply', arguments.length, 2); - } - - if (isNumber(x)) { - if (isNumber(y)) { - // number * number - return x * y; - } - else if (y instanceof Complex) { - // number * complex - return _multiplyComplex (new Complex(x, 0), y); - } - else if (y instanceof Unit) { - res = y.clone(); - res.value *= x; - return res; - } - } - else if (x instanceof Complex) { - if (isNumber(y)) { - // complex * number - return _multiplyComplex (x, new Complex(y, 0)); - } - else if (y instanceof Complex) { - // complex * complex - return _multiplyComplex (x, y); - } - } - else if (x instanceof Unit) { - if (isNumber(y)) { - res = x.clone(); - res.value *= y; - return res; - } - } - else if (Array.isArray(x)) { - if (Array.isArray(y)) { - // matrix * matrix - var sizeX = util.size(x); - var sizeY = util.size(y); - - if (sizeX.length != 2) { - throw new Error('Can only multiply a 2 dimensional matrix ' + - '(A has ' + sizeX.length + ' dimensions)'); - } - if (sizeY.length != 2) { - throw new Error('Can only multiply a 2 dimensional matrix ' + - '(B has ' + sizeY.length + ' dimensions)'); - } - if (sizeX[1] != sizeY[0]) { - throw new RangeError('Dimensions mismatch in multiplication. ' + - 'Columns of A must match rows of B ' + - '(A is ' + sizeX[0] + 'x' + sizeX[1] + - ', B is ' + sizeY[0] + 'x' + sizeY[1] + ', ' + - sizeY[1] + ' != ' + sizeY[0] + ')'); - } - - // TODO: performance of matrix multiplication can be improved - var res = [], - rows = sizeX[0], - cols = sizeY[1], - num = sizeX[1], - multiply = math.multiply, - add = math.add; - for (var r = 0; r < rows; r++) { - res[r] = []; - for (var c = 0; c < cols; c++) { - var result = null; - for (var n = 0; n < num; n++) { - var p = multiply(x[r][n], y[n][c]); - result = (result == null) ? p : add(result, p); - } - res[r][c] = result; - } - } - - return res; - } - else if (y instanceof Matrix) { - return new Matrix(math.multiply(x.valueOf(), y.valueOf())); - } - else { - // matrix * scalar - return util.map2(x, y, math.multiply); - } - } - else if (x instanceof Matrix) { - return new Matrix(math.multiply(x.valueOf(), y.valueOf())); - } - - if (Array.isArray(y)) { - // scalar * matrix - return util.map2(x, y, math.multiply); - } - else if (y instanceof Matrix) { - return new Matrix(math.multiply(x.valueOf(), y.valueOf())); - } - - if (x.valueOf() !== x || y.valueOf() !== y) { - // fallback on the objects primitive values - return math.multiply(x.valueOf(), y.valueOf()); - } - - throw newUnsupportedTypeError('multiply', x, y); -}; - -/** - * Multiply two complex numbers. x * y or multiply(x, y) - * @param {Complex} x - * @param {Complex} y - * @return {Complex | Number} res - * @private - */ -function _multiplyComplex (x, y) { - // Note: we test whether x or y are pure real or pure complex, - // to prevent unnecessary NaN values. For example, Infinity*i should - // result in Infinity*i, and not in NaN+Infinity*i - - if (x.im == 0) { - // x is pure real - if (y.im == 0) { - // y is pure real - return x.re * y.re; - } - else if (y.re == 0) { - // y is pure complex - return new Complex( - 0, - x.re * y.im - ); - } - else { - // y has a real and complex part - return new Complex( - x.re * y.re, - x.re * y.im - ); - } - } - else if (x.re == 0) { - // x is pure complex - if (y.im == 0) { - // y is pure real - return new Complex( - 0, - x.im * y.re - ); - } - else if (y.re == 0) { - // y is pure complex - return -x.im * y.im; - } - else { - // y has a real and complex part - return new Complex( - -x.im * y.im, - x.im * y.re - ); - } - } - else { - // x has a real and complex part - if (y.im == 0) { - // y is pure real - return new Complex( - x.re * y.re, - x.im * y.re - ); - } - else if (y.re == 0) { - // y is pure complex - return new Complex( - -x.im * y.im, - x.re * y.im - ); - } - else { - // y has a real and complex part - return new Complex( - x.re * y.re - x.im * y.im, - x.re * y.im + x.im * y.re - ); - } - } -} - -/** - * Calculates the power of x to y - * - * x ^ y - * pow(x, y) - * - * @param {Number | Complex | Array | Matrix} x - * @param {Number | Complex} y - * @return {Number | Complex | Array | Matrix} res - */ -math.pow = function pow(x, y) { - if (arguments.length != 2) { - throw newArgumentsError('pow', arguments.length, 2); - } - - if (isNumber(x)) { - if (isNumber(y)) { - if (isInteger(y) || x >= 0) { - // real value computation - return Math.pow(x, y); - } - else { - return powComplex(new Complex(x, 0), new Complex(y, 0)); - } - } - else if (y instanceof Complex) { - return powComplex(new Complex(x, 0), y); - } - } - else if (x instanceof Complex) { - if (isNumber(y)) { - return powComplex(x, new Complex(y, 0)); - } - else if (y instanceof Complex) { - return powComplex(x, y); - } - } - else if (Array.isArray(x)) { - if (!isNumber(y) || !isInteger(y) || y < 0) { - throw new TypeError('For A^b, b must be a positive integer ' + - '(value is ' + y + ')'); - } - // verify that A is a 2 dimensional square matrix - var s = util.size(x); - if (s.length != 2) { - throw new Error('For A^b, A must be 2 dimensional ' + - '(A has ' + s.length + ' dimensions)'); - } - if (s[0] != s[1]) { - throw new Error('For A^b, A must be square ' + - '(size is ' + s[0] + 'x' + s[1] + ')'); - } - - if (y == 0) { - // return the identity matrix - return math.eye(s[0]); - } - else { - // value > 0 - var res = x; - for (var i = 1; i < y; i++) { - res = math.multiply(x, res); - } - return res; - } - } - else if (x instanceof Matrix) { - return new Matrix(math.pow(x.valueOf(), y)); - } - - if (x.valueOf() !== x || y.valueOf() !== y) { - // fallback on the objects primitive values - return math.pow(x.valueOf(), y.valueOf()); - } - - throw newUnsupportedTypeError('pow', x, y); -}; - -/** - * Calculates the power of x to y, x^y, for two complex numbers. - * @param {Complex} x - * @param {Complex} y - * @return {Complex} res - * @private - */ -function powComplex (x, y) { - // complex computation - // x^y = exp(log(x)*y) = exp((abs(x)+i*arg(x))*y) - var temp1 = math.log(x); - var temp2 = math.multiply(temp1, y); - return math.exp(temp2); -} - -/** - * Round a value towards the nearest integer - * - * round(x) - * round(x, n) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @param {Number | Array} [n] number of decimals (by default n=0) - * @return {Number | Complex | Array | Matrix} res - */ -math.round = function round(x, n) { - if (arguments.length != 1 && arguments.length != 2) { - throw newArgumentsError('round', arguments.length, 1, 2); - } - - if (n == undefined) { - // round (x) - if (isNumber(x)) { - return Math.round(x); - } - - if (x instanceof Complex) { - return Complex.create ( - Math.round(x.re), - Math.round(x.im) - ); - } - - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.round); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.round(x.valueOf()); - } - - throw newUnsupportedTypeError('round', x); - } - else { - // round (x, n) - if (!isNumber(n)) { - throw new TypeError('Number of decimals in function round must be an integer'); - } - if (n !== Math.round(n)) { - throw new TypeError('Number of decimals in function round must be integer'); - } - if (n < 0 || n > 9) { - throw new Error ('Number of decimals in function round must be in te range of 0-9'); - } - - if (isNumber(x)) { - return roundNumber(x, n); - } - - if (x instanceof Complex) { - return Complex.create ( - roundNumber(x.re, n), - roundNumber(x.im, n) - ); - } - - if (Array.isArray(x) || x instanceof Matrix || - Array.isArray(n) || n instanceof Matrix) { - return util.map2(x, n, math.round); - } - - if (x.valueOf() !== x || n.valueOf() !== n) { - // fallback on the objects primitive values - return math.round(x.valueOf(), n.valueOf()); - } - - throw newUnsupportedTypeError('round', x, n); - } -}; - -/** - * round a number to the given number of decimals, or to zero if decimals is - * not provided - * @param {Number} value - * @param {Number} [decimals] number of decimals, between 0 and 15 (0 by default) - * @return {Number} roundedValue - */ -function roundNumber (value, decimals) { - if (decimals) { - var p = Math.pow(10, decimals); - return Math.round(value * p) / p; - } - else { - return Math.round(value); - } -} - -/** - * Compute the sign of a value. - * - * sign(x) - * - * The sign of a value x is 1 when x > 1, -1 when x < 0, and 0 when x == 0 - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ -math.sign = function sign(x) { - if (arguments.length != 1) { - throw newArgumentsError('sign', arguments.length, 1); - } - - if (isNumber(x)) { - var sign; - if (x > 0) { - sign = 1; - } - else if (x < 0) { - sign = -1; - } - else { - sign = 0; - } - return sign; - } - - if (x instanceof Complex) { - var abs = Math.sqrt(x.re * x.re + x.im * x.im); - return Complex.create(x.re / abs, x.im / abs); - } - - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.sign); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.sign(x.valueOf()); - } - - throw newUnsupportedTypeError('sign', x); -}; - -/** - * Check if value x is smaller y - * - * x < y - * smaller(x, y) - * - * For matrices, the function is evaluated element wise. - * In case of complex numbers, the absolute values of a and b are compared. - * - * @param {Number | Complex | Unit | String | Array | Matrix} x - * @param {Number | Complex | Unit | String | Array | Matrix} y - * @return {Boolean | Array | Matrix} res - */ -math.smaller = function smaller(x, y) { - if (arguments.length != 2) { - throw newArgumentsError('smaller', arguments.length, 2); - } - - if (isNumber(x)) { - if (isNumber(y)) { - return x < y; - } - else if (y instanceof Complex) { - return x < math.abs(y); - } - } - if (x instanceof Complex) { - if (isNumber(y)) { - return math.abs(x) < y; - } - else if (y instanceof Complex) { - return math.abs(x) < math.abs(y); - } - } - - if ((x instanceof Unit) && (y instanceof Unit)) { - if (!x.equalBase(y)) { - throw new Error('Cannot compare units with different base'); - } - return x.value < y.value; - } - - if (isString(x) || isString(y)) { - return x < y; - } - - if (Array.isArray(x) || x instanceof Matrix || - Array.isArray(y) || y instanceof Matrix) { - return util.map2(x, y, math.smaller); - } - - if (x.valueOf() !== x || y.valueOf() !== y) { - // fallback on the objects primitive values - return math.smaller(x.valueOf(), y.valueOf()); - } - - throw newUnsupportedTypeError('smaller', x, y); -}; - -/** - * Check if value a is smaller or equal to b - * - * a <= b - * smallereq(a, b) - * - * For matrices, the function is evaluated element wise. - * In case of complex numbers, the absolute values of a and b are compared. - * - * @param {Number | Complex | Unit | String | Array | Matrix} x - * @param {Number | Complex | Unit | String | Array | Matrix} y - * @return {Boolean | Array | Matrix} res - */ -math.smallereq = function smallereq(x, y) { - if (arguments.length != 2) { - throw newArgumentsError('smallereq', arguments.length, 2); - } - - if (isNumber(x)) { - if (isNumber(y)) { - return x <= y; - } - else if (y instanceof Complex) { - return x <= math.abs(y); - } - } - if (x instanceof Complex) { - if (isNumber(y)) { - return math.abs(x) <= y; - } - else if (y instanceof Complex) { - return math.abs(x) <= math.abs(y); - } - } - - if ((x instanceof Unit) && (y instanceof Unit)) { - if (!x.equalBase(y)) { - throw new Error('Cannot compare units with different base'); - } - return x.value <= y.value; - } - - if (isString(x) || isString(y)) { - return x <= y; - } - - if (Array.isArray(x) || x instanceof Matrix || - Array.isArray(y) || y instanceof Matrix) { - return util.map2(x, y, math.smallereq); - } - - if (x.valueOf() !== x || y.valueOf() !== y) { - // fallback on the objects primitive values - return math.smallereq(x.valueOf(), y.valueOf()); - } - - throw newUnsupportedTypeError('smallereq', x, y); -}; - -/** - * Calculate the square root of a value - * - * sqrt(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ -math.sqrt = function sqrt (x) { - if (arguments.length != 1) { - throw newArgumentsError('sqrt', arguments.length, 1); - } - - if (isNumber(x)) { - if (x >= 0) { - return Math.sqrt(x); - } - else { - return math.sqrt(new Complex(x, 0)); - } - } - - if (x instanceof Complex) { - var r = Math.sqrt(x.re * x.re + x.im * x.im); - if (x.im >= 0) { - return Complex.create( - 0.5 * Math.sqrt(2.0 * (r + x.re)), - 0.5 * Math.sqrt(2.0 * (r - x.re)) - ); - } - else { - return Complex.create( - 0.5 * Math.sqrt(2.0 * (r + x.re)), - -0.5 * Math.sqrt(2.0 * (r - x.re)) - ); - } - } - - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.sqrt); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.sqrt(x.valueOf()); - } - - throw newUnsupportedTypeError('sqrt', x); -}; - -/** - * Compute the square of a value - * - * x .* x - * square(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ -math.square = function square(x) { - if (arguments.length != 1) { - throw newArgumentsError('square', arguments.length, 1); - } - - if (isNumber(x)) { - return x * x; - } - - if (x instanceof Complex) { - return math.multiply(x, x); - } - - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.square); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.square(x.valueOf()); - } - - throw newUnsupportedTypeError('square', x); -}; - -/** - * Subtract two values - * - * x - y - * subtract(x, y) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Unit | Array | Matrix} x - * @param {Number | Complex | Unit | Array | Matrix} y - * @return {Number | Complex | Unit | Array | Matrix} res - */ -math.subtract = function subtract(x, y) { - if (arguments.length != 2) { - throw newArgumentsError('subtract', arguments.length, 2); - } - - if (isNumber(x)) { - if (isNumber(y)) { - // number - number - return x - y; - } - else if (y instanceof Complex) { - // number - complex - return Complex.create ( - x - y.re, - - y.im - ); - } - } - else if (x instanceof Complex) { - if (isNumber(y)) { - // complex - number - return Complex.create ( - x.re - y, - x.im - ) - } - else if (y instanceof Complex) { - // complex - complex - return Complex.create ( - x.re - y.re, - x.im - y.im - ) - } - } - else if (x instanceof Unit) { - if (y instanceof Unit) { - if (!x.equalBase(y)) { - throw new Error('Units do not match'); - } - - if (x.value == null) { - throw new Error('Unit on left hand side of operator - has an undefined value'); - } - - if (y.value == null) { - throw new Error('Unit on right hand side of operator - has an undefined value'); - } - - var res = x.clone(); - res.value -= y.value; - res.fixPrefix = false; - - return res; - } - } - - if (Array.isArray(x) || x instanceof Matrix || - Array.isArray(y) || y instanceof Matrix) { - return util.map2(x, y, math.subtract); - } - - if (x.valueOf() !== x || y.valueOf() !== y) { - // fallback on the objects primitive values - return math.subtract(x.valueOf(), y.valueOf()); - } - - throw newUnsupportedTypeError('subtract', x, y); -}; - -/** - * Inverse the sign of a value. - * - * -x - * unary(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Unit | Array | Matrix} x - * @return {Number | Complex | Unit | Array | Matrix} res - */ -math.unary = function unary(x) { - if (arguments.length != 1) { - throw newArgumentsError('unary', arguments.length, 1); - } - - if (isNumber(x)) { - return -x; - } - else if (x instanceof Complex) { - return Complex.create( - -x.re, - -x.im - ); - } - else if (x instanceof Unit) { - var res = x.clone(); - res.value = -x.value; - return res; - } - - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.unary); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.unary(x.valueOf()); - } - - throw newUnsupportedTypeError('unary', x); -}; - -// TODO: deprecated since version 0.10.0, cleanup some day -math.unaryminus = function unaryminus(x) { - throw new Error('Function unaryminus is deprecated, use unary instead'); -}; - -/** - * Check if value x unequals y, x != y - * In case of complex numbers, x.re must unequal y.re, or x.im must unequal y.im - * @param {Number | Complex | Unit | String | Array | Matrix | Range} x - * @param {Number | Complex | Unit | String | Array | Matrix | Range} y - * @return {Boolean | Array | Matrix} res - */ -math.unequal = function unequal(x, y) { - if (arguments.length != 2) { - throw newArgumentsError('unequal', arguments.length, 2); - } - - if (isNumber(x)) { - if (isNumber(y)) { - return x != y; - } - else if (y instanceof Complex) { - return (x != y.re) || (y.im != 0); - } - } - - if (x instanceof Complex) { - if (isNumber(y)) { - return (x.re != y) || (x.im != 0); - } - else if (y instanceof Complex) { - return (x.re != y.re) || (x.im != y.im); - } - } - - if ((x instanceof Unit) && (y instanceof Unit)) { - if (!x.equalBase(y)) { - throw new Error('Cannot compare units with different base'); - } - return x.value != y.value; - } - - if (isString(x) || isString(y)) { - return x != y; - } - - if (Array.isArray(x) || x instanceof Matrix || - Array.isArray(y) || y instanceof Matrix) { - return util.map2(x, y, math.unequal); - } - - if (x.valueOf() !== x || y.valueOf() !== y) { - // fallback on the objects primitive values - return math.unequal(x.valueOf(), y.valueOf()); - } - - throw newUnsupportedTypeError('unequal', x, y); -}; - -/** - * Calculate the extended greatest common divisor for two values. - * - * xgcd(a, b) - * - * @param {Number} a An integer number - * @param {Number} b An integer number - * @return {Array} An array containing 3 integers [div, m, n] - * where div = gcd(a, b) and a*m + b*n = div - * - * @see http://en.wikipedia.org/wiki/Extended_Euclidean_algorithm - */ -math.xgcd = function xgcd(a, b) { - if (arguments.length == 2) { - // two arguments - if (isNumber(a) && isNumber(b)) { - if (!isInteger(a) || !isInteger(b)) { - throw new Error('Parameters in function xgcd must be integer numbers'); - } - - if(b == 0) { - return [a, 1, 0]; - } - - var tmp = xgcd(b, a % b), - div = tmp[0], - x = tmp[1], - y = tmp[2]; - - return [div, y, x - y * Math.floor(a / b)]; - } - - throw newUnsupportedTypeError('xgcd', a, b); - } - - // zero or one argument - throw new SyntaxError('Function xgcd expects two arguments'); -}; - -/** - * Compute the argument of a complex value. - * If x = a + bi, the argument is computed as atan2(b, a). - * - * arg(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Array | Matrix} res - */ -math.arg = function arg(x) { - if (arguments.length != 1) { - throw newArgumentsError('arg', arguments.length, 1); - } - - if (isNumber(x)) { - return Math.atan2(0, x); - } - - if (x instanceof Complex) { - return Math.atan2(x.im, x.re); - } - - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.arg); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.arg(x.valueOf()); - } - - // handle other types just as non-complex values - return math.atan2(0, x); -}; - -/** - * Compute the complex conjugate of a complex value. - * If x = a+bi, the complex conjugate is a-bi. - * - * conj(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ -math.conj = function conj(x) { - if (arguments.length != 1) { - throw newArgumentsError('conj', arguments.length, 1); - } - - if (isNumber(x)) { - return x; - } - - if (x instanceof Complex) { - return Complex.create(x.re, -x.im); - } - - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.conj); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.conj(x.valueOf()); - } - - // return a clone of the value for non-complex values - return clone(x); -}; - -/** - * Get the imaginary part of a complex number. - * - * im(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Array | Matrix} im - */ -math.im = function im(x) { - if (arguments.length != 1) { - throw newArgumentsError('im', arguments.length, 1); - } - - if (isNumber(x)) { - return 0; - } - - if (x instanceof Complex) { - return x.im; - } - - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.im); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.im(x.valueOf()); - } - - // return 0 for all non-complex values - return 0; -}; - -/** - * Get the real part of a complex number. - * - * re(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Array | Matrix} re - */ -math.re = function re(x) { - if (arguments.length != 1) { - throw newArgumentsError('re', arguments.length, 1); - } - - if (isNumber(x)) { - return x; - } - - if (x instanceof Complex) { - return x.re; - } - - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.re); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.re(x.valueOf()); - } - - // return a clone of the value itself for all non-complex values - return math.clone(x); -}; - -/** - * Create a boolean or convert a string or number to a boolean. - * In case of a number, true is returned for non-zero numbers, and false in - * case of zero. - * Strings can be 'true' or 'false', or can contain a number. - * @param {String | Number | Boolean} value - * @return {Boolean} bool - */ -math['boolean'] = function (value) { - if (arguments.length != 1) { - throw newArgumentsError('boolean', arguments.length, 0, 1); - } - - if (value === 'true' || value === true) { - return true; - } - else if (value === 'false' || value === false) { - return false; - } - else if (isNumber(value)) { - return (value !== 0); - } - else if (isString(value)) { - // try case insensitive - var lcase = value.toLowerCase(); - if (lcase === 'true') { - return true; - } - else if (lcase === 'false') { - return false; - } - - // try whether a number - var num = Number(value); - if (value != '' && !isNaN(num)) { - return (num !== 0); - } - } - - throw new SyntaxError(value.toString() + ' is no valid boolean'); -}; - -/** - * Create a complex value. Depending on the passed arguments, the function - * will create and return a new math.type.Complex object. - * - * The method accepts the following arguments: - * complex() creates a complex value with zero - * as real and imaginary part. - * complex(re : number, im : string) creates a complex value with provided - * values for real and imaginary part. - * complex(arg : string) parses a string into a complex value. - * - * Example usage: - * var a = math.complex(3, -4); // 3 - 4i - * a.re = 5; // a = 5 - 4i - * var i = a.im; // -4; - * var b = math.complex('2 + 6i'); // 2 + 6i - * var c = math.complex(); // 0 + 0i - * var d = math.add(a, b); // 5 + 2i - * - * @param {*} [args] - * @return {Complex} value - */ -math.complex = function complex(args) { - switch (arguments.length) { - case 0: - // no parameters. Set re and im zero - return new Complex(0, 0); - break; - - case 1: - // parse string into a complex number - var arg = arguments[0]; - if (arg instanceof Complex) { - // create a clone - return arg.clone(); - } - else if (isString(arg)) { - var c = Complex.parse(arg); - if (c) { - return c; - } - else { - throw new SyntaxError('String "' + arg + '" is no valid complex number'); - } - } - else { - throw new TypeError( - 'Two numbers or a single string expected in function complex'); - } - break; - - case 2: - // re and im provided - return new Complex(arguments[0], arguments[1]); - break; - - default: - throw newArgumentsError('complex', arguments.length, 0, 2); - } -}; - -/** - * Create a matrix. The function creates a new math.type.Matrix object. - * - * The method accepts the following arguments: - * matrix() creates an empty matrix - * matrix(data) creates a matrix with initial data. - * - * Example usage: - * var m = matrix([[1, 2], [3, 4]); - * m.size(); // [2, 2] - * m.resize([3, 2], 5); - * m.valueOf(); // [[1, 2], [3, 4], [5, 5]] - * m.get([1, 0]) // 3 - * - * @param {Array | Matrix} [data] A multi dimensional array - * @return {Matrix} matrix - */ -math.matrix = function matrix(data) { - if (arguments.length > 1) { - throw newArgumentsError('matrix', arguments.length, 0, 1); - } - - return new Matrix(data); -}; - -/** - * Create a number or convert a string to a number - * @param {String | Number | Boolean} [value] - * @return {Number} num - */ -math.number = function (value) { - switch (arguments.length) { - case 0: - return 0; - case 1: - var num = Number(value); - if (isNaN(num)) { - num = Number(value.valueOf()); - } - if (isNaN(num)) { - throw new SyntaxError(value.toString() + ' is no valid number'); - } - return num; - default: - throw newArgumentsError('number', arguments.length, 0, 1); - } -}; - -/** - * Create a parser. The function creates a new math.expr.Parser object. - * - * parser() - * - * Example usage: - * var parser = new math.parser(); - * - * // evaluate expressions - * var a = parser.eval('sqrt(3^2 + 4^2)'); // 5 - * var b = parser.eval('sqrt(-4)'); // 2i - * var c = parser.eval('2 inch in cm'); // 5.08 cm - * var d = parser.eval('cos(45 deg)'); // 0.7071067811865476 - * - * // define variables and functions - * parser.eval('x = 7 / 2'); // 3.5 - * parser.eval('x + 3'); // 6.5 - * parser.eval('function f(x, y) = x^y'); // f(x, y) - * parser.eval('f(2, 3)'); // 8 - * - * // get and set variables and functions - * var x = parser.get('x'); // 7 - * var f = parser.get('f'); // function - * var g = f(3, 2); // 9 - * parser.set('h', 500); - * var i = parser.eval('h / 2'); // 250 - * parser.set('hello', function (name) { - * return 'hello, ' + name + '!'; - * }); - * parser.eval('hello("user")'); // "hello, user!" - * - * // clear defined functions and variables - * parser.clear(); - * - * @return {math.expr.Parser} Parser - */ -math.parser = function parser() { - return new math.expr.Parser(); -}; - -/** - * Create a range. The function creates a new math.type.Range object. - * - * A range works similar to an Array, with functions like - * forEach and map. However, a Range object is very cheap to create compared to - * a large Array with indexes, as it stores only a start, step and end value of - * the range. - * - * The method accepts the following arguments - * range(str) Create a range from a string, where the - * string contains the start, optional step, - * and end, separated by a colon. - * range(start, end) Create a range with start and end and a - * default step size of 1 - * range(start, step, end) Create a range with start, step, and end. - * - * Example usage: - * var c = math.range(2, 1, 5); // 2:1:5 - * c.toArray(); // [2, 3, 4, 5] - * var d = math.range(2, -1, -2); // 2:-1:-2 - * d.forEach(function (value, index) { - * console.log(index, value); - * }); - * var e = math.range('2:1:5'); // 2:1:5 - * - * @param {...*} args - * @return {Range} range - */ -math.range = function range(args) { - switch (arguments.length) { - case 1: - // parse string into a range - if (args instanceof Range) { - // create a clone - return args.clone(); - } - else if (isString(args)) { - var r = Range.parse(args); - if (r) { - return r; - } - else { - throw new SyntaxError('String "' + r + '" is no valid range'); - } - } - else { - throw new TypeError( - 'Two or three numbers or a single string expected in function range'); - } - break; - - case 2: - // range(start, end) - return new Range(arguments[0], null, arguments[1]); - break; - - case 3: - // range(start, step, end) - return new Range(arguments[0], arguments[1], arguments[2]); - break; - - default: - throw newArgumentsError('range', arguments.length, 2, 3); - } -}; - -/** - * Create a string or convert any object into a string - * @param {*} [value] - * @return {String} str - */ -math.string = function (value) { - switch (arguments.length) { - case 0: - return ''; - - case 1: - return _toString(value); - - default: - throw newArgumentsError('string', arguments.length, 0, 1); - } -}; - -/** - * Recursive toString function - * @param {*} value Value can be anything: number, string, array, Matrix, ... - * @returns {String} str - * @private - */ -function _toString(value) { - if (Array.isArray(value) || value instanceof Matrix || value instanceof Range) { - var array = value.valueOf(); - - var str = '['; - var len = array.length; - for (var i = 0; i < len; i++) { - if (i != 0) { - str += ', '; - } - str += _toString(array[i]); - } - str += ']'; - return str; - } - else if (isNumber(value)) { - return util.formatNumber(value); // no digits specified - } - else { - return value.toString(); - } -} -/** - * Create a unit. Depending on the passed arguments, the function - * will create and return a new math.type.Unit object. - * - * The method accepts the following arguments: - * unit(unit : string) - * unit(value : number, unit : string - * - * Example usage: - * var a = math.unit(5, 'cm'); // 50 mm - * var b = math.unit('23 kg'); // 23 kg - * var c = math.in(a, math.unit('m'); // 0.05 m - * - * @param {*} args - * @return {Unit} value - */ -math.unit = function unit(args) { - switch(arguments.length) { - case 1: - // parse a string - var arg = arguments[0]; - if (arg instanceof Unit) { - // create a clone of the unit - return arg.clone(); - } - else if (isString(arg)) { - if (Unit.isPlainUnit(arg)) { - return new Unit(null, arg); // a pure unit - } - - var u = Unit.parse(arg); // a unit with value, like '5cm' - if (u) { - return u; - } - - throw new SyntaxError('String "' + arg + '" is no valid unit'); - } - else { - throw new TypeError('A string or a number and string expected in function unit'); - } - break; - - case 2: - // a number and a unit - return new Unit(arguments[0], arguments[1]); - break; - - default: - throw newArgumentsError('unit', arguments.length, 1, 2); - } -}; - -math.workspace = function () { - throw new Error('Workspace is no longer supported, sorry...'); -}; -/** - * Concatenate two or more matrices - * Usage: - * math.concat(A, B, C, ...) - * math.concat(A, B, C, ..., dim) - * - * Where the optional dim is the zero-based number of the dimension to be - * concatenated. - * - * @param {... Array | Matrix} args - * @return {Array | Matrix} res - */ -math.concat = function concat (args) { - var i, - len = arguments.length, - dim = -1, // zero-based dimension - prevDim, - asMatrix = false, - matrices = []; // contains multi dimensional arrays - - for (i = 0; i < len; i++) { - var arg = arguments[i]; - - // test whether we need to return a Matrix (if not we return an Array) - if (arg instanceof Matrix) { - asMatrix = true; - } - - if ((i == len - 1) && isNumber(arg)) { - // last argument contains the dimension on which to concatenate - prevDim = dim; - dim = arg; - - if (!isInteger(dim) || dim < 0) { - throw new TypeError('Dimension number must be a positive integer ' + - '(dim = ' + dim + ')'); - } - - if (i > 0 && dim > prevDim) { - throw new RangeError('Dimension out of range ' + - '(' + dim + ' > ' + prevDim + ')'); - } - } - else if (Array.isArray(arg) || arg instanceof Matrix) { - // this is a matrix or array - var matrix = math.clone(arg).valueOf(); - var size = math.size(arg).valueOf(); - matrices[i] = matrix; - prevDim = dim; - dim = size.length - 1; - - // verify whether each of the matrices has the same number of dimensions - if (i > 0 && dim != prevDim) { - throw new RangeError('Dimension mismatch ' + - '(' + prevDim + ' != ' + dim + ')'); - } - } - else { - throw newUnsupportedTypeError('concat', arg); - } - } - - if (matrices.length == 0) { - throw new SyntaxError('At least one matrix expected'); - } - - var res = matrices.shift(); - while (matrices.length) { - res = _concat(res, matrices.shift(), dim, 0); - } - - return asMatrix ? new Matrix(res) : res; -}; - -/** - * Recursively concatenate two matrices. - * The contents of the matrices is not cloned. - * @param {Array} a Multi dimensional array - * @param {Array} b Multi dimensional array - * @param {Number} concatDim The dimension on which to concatenate (zero-based) - * @param {Number} dim The current dim (zero-based) - * @return {Array} c The concatenated matrix - * @private - */ -function _concat(a, b, concatDim, dim) { - if (dim < concatDim) { - // recurse into next dimension - if (a.length != b.length) { - throw new Error('Dimensions mismatch (' + a.length + ' != ' + b.length + ')'); - } - - var c = []; - for (var i = 0; i < a.length; i++) { - c[i] = _concat(a[i], b[i], concatDim, dim + 1); - } - return c; - } - else { - // concatenate this dimension - return a.concat(b); - } -} - -/** - * @constructor det - * Calculate the determinant of a matrix - * - * det(x) - * - * @param {Array | Matrix} x - * @return {Number} determinant - */ -math.det = function det (x) { - if (arguments.length != 1) { - throw newArgumentsError('det', arguments.length, 1); - } - - var size = math.size(x).valueOf(); - switch (size.length) { - case 0: - // scalar - return math.clone(x); - break; - - case 1: - // vector - if (size[0] == 1) { - return math.clone(x.valueOf()[0]); - } - else { - throw new RangeError('Matrix must be square ' + - '(size: ' + math.format(size) + ')'); - } - break; - - case 2: - // two dimensional array - var rows = size[0]; - var cols = size[1]; - if (rows == cols) { - return _det(x.valueOf(), rows, cols); - } - else { - throw new RangeError('Matrix must be square ' + - '(size: ' + math.format(size) + ')'); - } - break; - - default: - // multi dimensional array - throw new RangeError('Matrix must be two dimensional ' + - '(size: ' + math.format(size) + ')'); - } -}; - -/** - * Calculate the determinant of a matrix - * @param {Array[]} matrix A square, two dimensional matrix - * @param {Number} rows Number of rows of the matrix (zero-based) - * @param {Number} cols Number of columns of the matrix (zero-based) - * @returns {Number} det - * @private - */ -function _det (matrix, rows, cols) { - var multiply = math.multiply, - subtract = math.subtract; - - if (rows == 1) { - // this is a 1 x 1 matrix - return matrix[0][0]; - } - else if (rows == 2) { - // this is a 2 x 2 matrix - // the determinant of [a11,a12;a21,a22] is det = a11*a22-a21*a12 - return subtract( - multiply(matrix[0][0], matrix[1][1]), - multiply(matrix[1][0], matrix[0][1]) - ); - } - else { - // this is an n x n matrix - var det = 1; - var lead = 0; - for (var r = 0; r < rows; r++) { - if (lead >= cols) { - break; - } - var i = r; - // Find the pivot element. - while (matrix[i][lead] == 0) { - i++; - if (i == rows) { - i = r; - lead++; - if (lead == cols) { - // We found the last pivot. - if (util.deepEqual(matrix, math.eye(rows).valueOf())) { - return math.round(det, 6); - } else { - return 0; - } - } - } - } - if (i != r) { - // Swap rows i and r, which negates the determinant. - for (var a = 0; a < cols; a++) { - var temp = matrix[i][a]; - matrix[i][a] = matrix[r][a]; - matrix[r][a] = temp; - } - det *= -1; - } - // Scale row r and the determinant simultaneously. - var div = matrix[r][lead]; - for (var a = 0; a < cols; a++) { - matrix[r][a] = matrix[r][a] / div; - } - det *= div; - // Back-substitute upwards. - for (var j = 0; j < rows; j++) { - if (j != r) { - // Taking linear combinations does not change the det. - var c = matrix[j][lead]; - for (var a = 0; a < cols; a++) { - matrix[j][a] = matrix[j][a] - matrix[r][a] * c; - } - } - } - lead++; // Now looking for a pivot further right. - } - // If reduction did not result in the identity, the matrix is singular. - if (util.deepEqual(matrix, math.eye(rows).valueOf())) { - return math.round(det, 6); - } else { - return 0; - } - } -} - -/** - * Create a diagonal matrix or retrieve the diagonal of a matrix - * - * diag(v) - * diag(v, k) - * diag(X) - * diag(X, k) - * - * TODO: more documentation on diag - * - * @param {Number | Matrix | Array} x - * @param {Number} [k] - * @return {Matrix} matrix - */ -math.diag = function diag (x, k) { - var data, vector, i, iMax; - - if (arguments.length != 1 && arguments.length != 2) { - throw newArgumentsError('diag', arguments.length, 1, 2); - } - - if (k) { - if (!isNumber(k) || !isInteger(k)) { - throw new TypeError ('Second parameter in function diag must be an integer'); - } - } - else { - k = 0; - } - var kSuper = k > 0 ? k : 0; - var kSub = k < 0 ? -k : 0; - - // convert to matrix - if (!(x instanceof Matrix) && !(x instanceof Range)) { - x = new Matrix(x); - } - - // get as array when the matrix is a vector - var s; - if (x.isVector()) { - x = x.toVector(); - s = [x.length]; - } - else { - s = x.size(); - } - - switch (s.length) { - case 1: - // x is a vector. create diagonal matrix - vector = x.valueOf(); - var matrix = new Matrix(); - matrix.resize([vector.length + kSub, vector.length + kSuper]); - data = matrix.valueOf(); - iMax = vector.length; - for (i = 0; i < iMax; i++) { - data[i + kSub][i + kSuper] = math.clone(vector[i]); - } - return matrix; - break; - - case 2: - // x is a matrix get diagonal from matrix - vector = []; - data = x.valueOf(); - iMax = Math.min(s[0] - kSub, s[1] - kSuper); - for (i = 0; i < iMax; i++) { - vector[i] = math.clone(data[i + kSub][i + kSuper]); - } - return new Matrix(vector); - break; - - default: - throw new RangeError('Matrix for function diag must be 2 dimensional'); - } -}; - -/** - * Create an identity matrix with size m x n - * - * eye(m) - * eye(m, n) - * - * TODO: more documentation on eye - * - * @param {...Number | Matrix | Array} size - * @return {Matrix} matrix - */ -math.eye = function eye (size) { - var args = util.argsToArray(arguments); - if (args.length == 0) { - args = [1, 1]; - } - else if (args.length == 1) { - args[1] = args[0]; - } - else if (args.length > 2) { - throw newArgumentsError('eye', args.length, 0, 2); - } - - var rows = args[0], - cols = args[1]; - - if (!isNumber(rows) || !isInteger(rows) || rows < 1) { - throw new Error('Parameters in function eye must be positive integers'); - } - if (cols) { - if (!isNumber(cols) || !isInteger(cols) || cols < 1) { - throw new Error('Parameters in function eye must be positive integers'); - } - } - - // create and args the matrix - var matrix = new Matrix(); - matrix.resize(args); - - // fill in ones on the diagonal - var min = math.min(args); - var data = matrix.valueOf(); - for (var d = 0; d < min; d++) { - data[d][d] = 1; - } - - return matrix; -}; - -/** - * Calculate the inverse of a matrix - * - * inv(x) - * - * TODO: more documentation on inv - * - * @param {Array | Matrix} x - * @return {Array | Matrix} inv - */ -math.inv = function inv (x) { - if (arguments.length != 1) { - throw newArgumentsError('inv', arguments.length, 1); - } - - var size = math.size(x).valueOf(); - switch (size.length) { - case 0: - // scalar - return math.divide(1, x); - break; - - case 1: - // vector - if (size[0] == 1) { - if (x instanceof Matrix) { - return new Matrix([ - math.divide(1, x.valueOf()[0]) - ]); - } - else { - return [ - math.divide(1, x[0]) - ]; - } - } - else { - throw new RangeError('Matrix must be square ' + - '(size: ' + math.format(size) + ')'); - } - break; - - case 2: - // two dimensional array - var rows = size[0]; - var cols = size[1]; - if (rows == cols) { - if (x instanceof Matrix) { - return new Matrix( - _inv(x.valueOf(), rows, cols) - ); - } - else { - // return an Array - return _inv(x, rows, cols); - } - } - else { - throw new RangeError('Matrix must be square ' + - '(size: ' + math.format(size) + ')'); - } - break; - - default: - // multi dimensional array - throw new RangeError('Matrix must be two dimensional ' + - '(size: ' + math.format(size) + ')'); - } -}; - -/** - * Calculate the inverse of a square matrix - * @param {Array[]} matrix A square matrix - * @param {Number} rows Number of rows - * @param {Number} cols Number of columns, must equal rows - * @return {Array[]} inv Inverse matrix - * @private - */ -function _inv (matrix, rows, cols){ - var r, s, f, value, temp, - add = math.add, - unary = math.unary, - multiply = math.multiply, - divide = math.divide; - - if (rows == 1) { - // this is a 1 x 1 matrix - value = matrix[0][0]; - if (value == 0) { - throw Error('Cannot calculate inverse, determinant is zero'); - } - return [[ - divide(1, value) - ]]; - } - else if (rows == 2) { - // this is a 2 x 2 matrix - var det = math.det(matrix); - if (det == 0) { - throw Error('Cannot calculate inverse, determinant is zero'); - } - return [ - [ - divide(matrix[1][1], det), - divide(unary(matrix[0][1]), det) - ], - [ - divide(unary(matrix[1][0]), det), - divide(matrix[0][0], det) - ] - ]; - } - else { - // this is a matrix of 3 x 3 or larger - // calculate inverse using gauss-jordan elimination - // http://en.wikipedia.org/wiki/Gaussian_elimination - // http://mathworld.wolfram.com/MatrixInverse.html - // http://math.uww.edu/~mcfarlat/inverse.htm - - // make a copy of the matrix (only the arrays, not of the elements) - var A = matrix.concat(); - for (r = 0; r < rows; r++) { - A[r] = A[r].concat(); - } - - // create an identity matrix which in the end will contain the - // matrix inverse - var B = math.eye(rows).valueOf(); - - // loop over all columns, and perform row reductions - for (var c = 0; c < cols; c++) { - // element Acc should be non zero. if not, swap content - // with one of the lower rows - r = c; - while (r < rows && A[r][c] == 0) { - r++; - } - if (r == rows || A[r][c] == 0) { - throw Error('Cannot calculate inverse, determinant is zero'); - } - if (r != c) { - temp = A[c]; A[c] = A[r]; A[r] = temp; - temp = B[c]; B[c] = B[r]; B[r] = temp; - } - - // eliminate non-zero values on the other rows at column c - var Ac = A[c], - Bc = B[c]; - for (r = 0; r < rows; r++) { - var Ar = A[r], - Br = B[r]; - if(r != c) { - // eliminate value at column c and row r - if (Ar[c] != 0) { - f = divide(unary(Ar[c]), Ac[c]); - - // add (f * row c) to row r to eliminate the value - // at column c - for (s = c; s < cols; s++) { - Ar[s] = add(Ar[s], multiply(f, Ac[s])); - } - for (s = 0; s < cols; s++) { - Br[s] = add(Br[s], multiply(f, Bc[s])); - } - } - } - else { - // normalize value at Acc to 1, - // divide each value on row r with the value at Acc - f = Ac[c]; - for (s = c; s < cols; s++) { - Ar[s] = divide(Ar[s], f); - } - for (s = 0; s < cols; s++) { - Br[s] = divide(Br[s], f); - } - } - } - } - return B; - } -} - -/** - * Create a matrix filled with ones - * - * ones(n) - * ones(m, n) - * ones([m, n]) - * ones([m, n, p, ...]) - * - * @param {...Number | Array} size - * @return {Matrix} matrix - */ -math.ones = function ones (size) { - var args = util.argsToArray(arguments); - - if (args.length == 0) { - args = [1, 1]; - } - else if (args.length == 1) { - args[1] = args[0]; - } - - // create and size the matrix - var matrix = new Matrix(); - var defaultValue = 1; - matrix.resize(args, defaultValue); - return matrix; -}; - -/** - * Calculate the size of a matrix or scalar - * - * size(x) - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ -math.size = function size (x) { - if (arguments.length != 1) { - throw newArgumentsError('size', arguments.length, 1); - } - - if (isNumber(x) || x instanceof Complex || x instanceof Unit || x == null) { - return []; - } - - if (isString(x)) { - return [x.length]; - } - - if (Array.isArray(x)) { - return util.size(x); - } - - if (x instanceof Matrix) { - return new Matrix(x.size()); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.size(x.valueOf()); - } - - throw newUnsupportedTypeError('size', x); -}; - -/** - * Remove singleton dimensions from a matrix - * - * squeeze(x) - * - * @param {Matrix | Array} x - * @return {Matrix | Array} res - */ -math.squeeze = function squeeze (x) { - if (arguments.length != 1) { - throw newArgumentsError('squeeze', arguments.length, 1); - } - - if (Array.isArray(x)) { - return _squeezeArray(math.clone(x)); - } - else if (x instanceof Matrix) { - return math.matrix(_squeezeArray(x.toArray())); - } - else if (Array.isArray(x.valueOf())) { - return _squeezeArray(math.clone(x.valueOf())); - } - else { - // scalar - return math.clone(x); - } -}; - -/** - * Recursively squeeze a multi dimensional array - * @param {Array} array - * @return {Array} array - * @private - */ -function _squeezeArray(array) { - if (array.length == 1) { - // squeeze this array - return _squeezeArray(array[0]); - } - else { - // process all childs - for (var i = 0, len = array.length; i < len; i++) { - var child = array[i]; - if (Array.isArray(child)) { - array[i] = _squeezeArray(child); - } - } - return array; - } -} - -/** - * Get or set a subset of a matrix or string - * - * Usage: - * var subset = math.subset(value, index) // retrieve subset - * var value = math.subset(value, index, replacement) // replace subset - * - * Where: - * {*} value An array, matrix, or scalar value - * {Array} index An array containing index values - * {*} replacement An array, matrix, or scalar - * - * @param args - * @return res - */ -math.subset = function subset (args) { - switch (arguments.length) { - case 2: // get subset - return _getSubset(arguments[0], arguments[1]); - - case 3: // set subset - return _setSubset(arguments[0], arguments[1], arguments[2]); - - default: // wrong number of arguments - throw newArgumentsError('subset', arguments.length, 2, 3); - } -}; - -/** - * Retrieve a subset of an value such as an Array, Matrix, or String - * @param {*} value Object from which to get a subset - * @param {Array[] | Range[] | Number[] | Matrix} index - * Two dimensional array (size 1 x n) containing - * the indexes to be retrieved. Can also be a two - * dimensional Matrix (size 1 x n), or an Array - * (size 1) containing a Range or a Number. - * @returns {*} subset - * @private - */ -function _getSubset(value, index) { - var matrix, subset; - - if (Array.isArray(value) || value instanceof Range) { - matrix = math.matrix(value); - subset = matrix.get(index); - return subset.valueOf(); - } - else if (value instanceof Matrix) { - return value.get(index); - } - else if (isString(value)) { - return _getSubstring(value, index); - } - else { - // scalar - matrix = math.matrix([value]); - subset = matrix.get(index); - return subset.valueOf(); - } -} - -/** - * Retrieve a subset of a string - * @param {String} str String from which to get a substring - * @param {Array[] | Range[] | Number[] | Matrix} index - * Two dimensional array (size 1 x n) containing - * the indexes to be retrieved. Can also be a two - * dimensional Matrix (size 1 x n), or an Array - * (size 1) containing a Range or a Number. - * @returns {string} substring - * @private - */ -function _getSubstring(str, index) { - var i, len; - index = index.valueOf(); // cast from matrix or range to array - if (index.length != 1) { - throw new RangeError('Dimension mismatch (' + index.length + ' != 1)'); - } - - if (Array.isArray(index)) { - index = index[0]; // read first dimension - } - index = index.valueOf(); // cast from matrix or range to array - if (!Array.isArray(index)) { - index = [index]; - } - - var substr = ''; - var strLen = str.length; - for (i = 0, len = index.length; i < len; i++) { - var index_i = index[i]; - util.validateIndex(index_i, strLen); - substr += str.charAt(index_i); // index_i is zero based - } - - return substr; -} - -/** - * Replace a subset in an value such as an Array, Matrix, or String - * @param {*} value Object to be replaced - * @param {Array[] | Range[] | Number[] | Matrix} index - * Two dimensional array (size 1 x n) containing - * the indexes to be replaced. Can also be a two - * dimensional Matrix (size 1 x n), or an Array - * (size 1) containing a Range. - * @param {String} replacement - * @returns {*} result - * @private - */ -function _setSubset(value, index, replacement) { - if (Array.isArray(value) || value instanceof Range) { - var matrix = math.matrix(math.clone(value)); - matrix.set(index, replacement); - return matrix.valueOf(); - } - else if (value instanceof Matrix) { - return value.clone().set(index, replacement); - } - else if (isString(value)) { - return _setSubstring(value, index, replacement); - } - else { - // scalar - matrix = math.matrix([value]); - matrix.set(index, replacement); - - if (matrix.isScalar()) { - // still a scalar - return matrix.toScalar(); - } - else { - // changed into a matrix. return array - return matrix.valueOf(); - } - } -} - -/** - * Replace a substring in a string - * @param {String} str String to be replaced - * @param {Array[] | Range[] | Number[] | Matrix} index - * Two dimensional array (size 1 x n) containing - * the indexes to be replaced. Can also be a two - * dimensional Matrix (size 1 x n), or an Array - * (size 1) containing a Range. - * @param {String} replacement Replacement string - * @returns {string} result - * @private - */ -function _setSubstring(str, index, replacement) { - var i, len; - index = index.valueOf(); // cast from matrix or range to array - - if (index.length != 1) { - throw new RangeError('Dimension mismatch (' + index.length + ' != 1)'); - } - if (Array.isArray(index)) { - index = index[0]; // read first dimension - } - index = index.valueOf(); // cast from matrix or range to array - if (!Array.isArray(index)) { - index = [index]; - } - - if (index.length != replacement.length) { - throw new RangeError('Dimension mismatch ' + - '(' + index.length + ' != ' + replacement.length + ')'); - } - - // copy the string into an array with characters - var strLen = str.length; - var chars = []; - for (i = 0; i < strLen; i++) { - chars[i] = str.charAt(i); - } - - for (i = 0, len = index.length; i < len; i++) { - var index_i = index[i]; - util.validateIndex(index_i); - chars[index_i] = replacement.charAt(i); // index_i is zero based - } - - // initialize undefined characters with a space - if (chars.length > strLen) { - for (i = strLen - 1, len = chars.length; i < len; i++) { - if (!chars[i]) { - chars[i] = ' '; - } - } - } - - return chars.join(''); -} - -/** - * Create the transpose of a matrix - * - * transpose(x) - * - * @param {Array | Matrix} x - * @return {Array | Matrix} transpose - */ -math.transpose = function transpose (x) { - if (arguments.length != 1) { - throw newArgumentsError('transpose', arguments.length, 1); - } - - var size = math.size(x).valueOf(); - switch (size.length) { - case 0: - // scalar - return math.clone(x); - break; - - case 1: - // vector - // TODO: is it logic to return a 1 dimensional vector itself as transpose? - return math.clone(x); - break; - - case 2: - // two dimensional array - var rows = size[1], // index 1 is no error - cols = size[0], // index 0 is no error - asMatrix = x instanceof Matrix, - array = x.valueOf(), - transposed = [], - transposedRow, - clone = math.clone; - for (var r = 0; r < rows; r++) { - transposedRow = transposed[r] = []; - for (var c = 0; c < cols; c++) { - transposedRow[c] = clone(array[c][r]); - } - } - if (cols == 0) { - transposed[0] = []; - } - return asMatrix ? new Matrix(transposed) : transposed; - break; - - default: - // multi dimensional array - throw new RangeError('Matrix must be two dimensional ' + - '(size: ' + math.format(size) + ')'); - } -}; - -/** - * create a matrix filled with zeros - * - * zeros(n) - * zeros(m, n) - * zeros([m, n]) - * zeros([m, n, p, ...]) - * - * @param {...Number | Array} size - * @return {Matrix} matrix - */ -math.zeros = function zeros (size) { - var args = util.argsToArray(arguments); - - if (args.length == 0) { - args = [1, 1]; - } - else if (args.length == 1) { - args[1] = args[0]; - } - - // create and size the matrix - var matrix = new Matrix(); - matrix.resize(args); - return matrix; -}; - -/** - * Compute the factorial of a value - * - * x! - * factorial(x) - * - * Factorial only supports an integer value as argument. - * For matrices, the function is evaluated element wise. - * - * @Param {Number | Array | Matrix} x - * @return {Number | Array | Matrix} res - */ -math.factorial = function factorial (x) { - if (arguments.length != 1) { - throw newArgumentsError('factorial', arguments.length, 1); - } - - if (isNumber(x)) { - if (!isInteger(x) || x < 0) { - throw new TypeError('Positive integer value expected in function factorial'); - } - - var value = x, - res = value; - value--; - while (value > 1) { - res *= value; - value--; - } - - if (res == 0) { - res = 1; // 0! is per definition 1 - } - - return res; - } - - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.factorial); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.factorial(x.valueOf()); - } - - throw newUnsupportedTypeError('factorial', x); -}; - -/** - * Return a random number between 0 and 1 - * - * random() - * - * @return {Number} res - */ - -// Each distribution is a function that takes no argument and when called returns -// a number between 0 and 1. -var distributions = { - - uniform: function() { - return Math.random; - }, - - // Implementation of normal distribution using Box-Muller transform - // ref : http://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform - // We take : mean = 0.5, standard deviation = 1/6 - // so that 99.7% values are in [0, 1]. - normal: function() { - return function() { - var u1, u2, - picked = -1; - // We reject values outside of the interval [0, 1] - // TODO: check if it is ok to do that? - while (picked < 0 || picked > 1) { - u1 = Math.random(); - u2 = Math.random(); - picked = 1/6 * Math.pow(-2 * Math.log(u1), 0.5) * Math.cos(2 * Math.PI * u2) + 0.5; - } - return picked; - } - } -}; - -/** - * Create a distribution object. - * @param {String} name Name of a distribution. - * Choose from 'uniform', 'normal'. - * @return {Object} distribution A distribution object containing functions: - * random([size, min, max]) - * randomInt([min, max]) - * pickRandom(array) - */ -math.distribution = function(name) { - if (!distributions.hasOwnProperty(name)) - throw new Error('unknown distribution ' + name); - - var args = Array.prototype.slice.call(arguments, 1), - distribution = distributions[name].apply(this, args); - - return (function(distribution) { - - // This is the public API for all distributions - var randFunctions = { - - random: function(arg1, arg2, arg3) { - var size, min, max - if (arguments.length > 3) { - throw newArgumentsError(funcName, argCount, 0, 3); - - // `random(max)` or `random(size)` - } else if (arguments.length === 1) { - if (Object.prototype.toString.call(arg1) === '[object Array]') - size = arg1 - else max = arg1 - // `random(min, max)` or `random(size, max)` - } else if (arguments.length === 2) { - if (Object.prototype.toString.call(arg1) === '[object Array]') - size = arg1 - else { - min = arg1 - max = arg2 - } - // `random(size, min, max)` - } else { - size = arg1 - min = arg2 - max = arg3 - } - - if (max === undefined) max = 1; - if (min === undefined) min = 0; - if (size !== undefined) return new Matrix(_randomDataForMatrix(size, min, max, _random)); - else return _random(min, max); - }, - - randomInt: function(arg1, arg2, arg3) { - var size, min, max - if (arguments.length > 3 || arguments.length < 1) - throw newArgumentsError(funcName, argCount, 1, 3); - - // `random(max)` - else if (arguments.length === 1) max = arg1 - // `random(min, max)` or `random(size, max)` - else if (arguments.length === 2) { - if (Object.prototype.toString.call(arg1) === '[object Array]') - size = arg1 - else { - min = arg1 - max = arg2 - } - // `random(size, min, max)` - } else { - size = arg1 - min = arg2 - max = arg3 - } - - if (min === undefined) min = 0; - if (size !== undefined) return new Matrix(_randomDataForMatrix(size, min, max, _randomInt)); - else return _randomInt(min, max); - }, - - pickRandom: function(possibles) { - if (arguments.length !== 1) - throw newArgumentsError('pickRandom', arguments.length, 1); - return possibles[Math.floor(Math.random() * possibles.length)]; - } - - }; - - var _random = function(min, max) { - return min + distribution() * (max - min); - }; - - var _randomInt = function(min, max) { - return Math.floor(min + distribution() * (max - min)); - }; - - // This is a function for generating a random matrix recursively. - var _randomDataForMatrix = function(size, min, max, randFunc) { - var data = [], length, i; - size = size.slice(0); - - if (size.length > 1) { - for (i = 0, length = size.shift(); i < length; i++) - data.push(_randomDataForMatrix(size, min, max, randFunc)); - } else { - for (i = 0, length = size.shift(); i < length; i++) - data.push(randFunc(min, max)); - } - - return data; - }; - - return randFunctions; - - })(distribution); - -}; - -// Default random functions use uniform distribution -var uniformRandFunctions = math.distribution('uniform'); -math.random = uniformRandFunctions.random; -math.randomInt = uniformRandFunctions.randomInt; -math.pickRandom = uniformRandFunctions.pickRandom; - -/** - * Compute the maximum value of a list of values - * - * max(a, b, c, ...) - * max([a, b, c, ...]) - * - * @param {... *} args A single matrix or or multiple scalar values - * @return {*} res - */ -math.max = function max(args) { - if (arguments.length == 0) { - throw new Error('Function max requires one or more parameters (0 provided)'); - } - - if (Array.isArray(args) || args instanceof Matrix || args instanceof Range) { - // max([a, b, c, d, ...]]) - if (arguments.length > 1) { - throw Error('Wrong number of parameters (1 matrix or multiple scalars expected)'); - } - - var size = math.size(args).valueOf(); - - if (size.length == 1) { - // vector - if (args.length == 0) { - throw new Error('Cannot calculate max of an empty vector'); - } - - return _max(args.valueOf()); - } - else if (size.length == 2) { - // 2 dimensional matrix - if (size[0] == 0 || size[1] == 0) { - throw new Error('Cannot calculate max of an empty matrix'); - } - if (Array.isArray(args)) { - return _max2(args, size[0], size[1]); - } - else if (args instanceof Matrix || args instanceof Range) { - return new Matrix(_max2(args.valueOf(), size[0], size[1])); - } - else { - throw newUnsupportedTypeError('max', args); - } - } - else { - // TODO: implement max for n-dimensional matrices - throw new RangeError('Cannot calculate max for multi dimensional matrix'); - } - } - else { - // max(a, b, c, d, ...) - return _max(arguments); - } -}; - -/** - * Calculate the max of a one dimensional array - * @param {Array} array - * @return {Number} max - * @private - */ -function _max(array) { - var larger = math.larger; - var res = array[0]; - for (var i = 1, iMax = array.length; i < iMax; i++) { - var value = array[i]; - if (larger(value, res)) { - res = value; - } - } - return res; -} - -/** - * Calculate the max of a two dimensional array - * @param {Array} array - * @param {Number} rows - * @param {Number} cols - * @return {Number[]} max - * @private - */ -function _max2(array, rows, cols) { - var larger = math.larger; - var res = []; - for (var c = 0; c < cols; c++) { - var max = array[0][c]; - for (var r = 1; r < rows; r++) { - var value = array[r][c]; - if (larger(value, max)) { - max = value; - } - } - res[c] = max; - } - return res; -} - -/** - * Compute the minimum value of a list of values - * - * min(a, b, c, ...) - * min([a, b, c, ...]) - * - * @param {... *} args A single matrix or multiple scalars - * @return {*} res - */ -math.min = function min(args) { - if (arguments.length == 0) { - throw new Error('Function min requires one or more parameters (0 provided)'); - } - - if (Array.isArray(args) || args instanceof Matrix || args instanceof Range) { - // min([a, b, c, d, ...]]) - if (arguments.length > 1) { - throw Error('Wrong number of parameters (1 matrix or multiple scalars expected)'); - } - - var size = math.size(args).valueOf(); - - if (size.length == 1) { - // vector - if (args.length == 0) { - throw new Error('Cannot calculate min of an empty vector'); - } - - return _min(args.valueOf()); - } - else if (size.length == 2) { - // 2 dimensional matrix - if (size[0] == 0 || size[1] == 0) { - throw new Error('Cannot calculate min of an empty matrix'); - } - if (Array.isArray(args)) { - return _min2(args, size[0], size[1]); - } - else if (args instanceof Matrix || args instanceof Range) { - return new Matrix(_min2(args.valueOf(), size[0], size[1])); - } - else { - throw newUnsupportedTypeError('min', args); - } - } - else { - // TODO: implement min for n-dimensional matrices - throw new RangeError('Cannot calculate min for multi dimensional matrix'); - } - } - else { - // min(a, b, c, d, ...) - return _min(arguments); - } -}; - -/** - * Calculate the min of a one dimensional array - * @param {Array} array - * @return {Number} min - * @private - */ -function _min(array) { - var smaller = math.smaller; - var res = array[0]; - for (var i = 1, iMax = array.length; i < iMax; i++) { - var value = array[i]; - if (smaller(value, res)) { - res = value; - } - } - return res; -} - -/** - * Calculate the min of a two dimensional array - * @param {Array} array - * @param {Number} rows - * @param {Number} cols - * @return {Number[]} min - * @private - */ -function _min2(array, rows, cols) { - var smaller = math.smaller; - var res = []; - for (var c = 0; c < cols; c++) { - var min = array[0][c]; - for (var r = 1; r < rows; r++) { - var value = array[r][c]; - if (smaller(value, min)) { - min = value; - } - } - res[c] = min; - } - return res; -} - -/** - * Calculate the inverse cosine of a value - * - * acos(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - * - * @see http://mathworld.wolfram.com/InverseCosine.html - */ -math.acos = function acos(x) { - if (arguments.length != 1) { - throw newArgumentsError('acos', arguments.length, 1); - } - - if (isNumber(x)) { - if (x >= -1 && x <= 1) { - return Math.acos(x); - } - else { - return math.acos(new Complex(x, 0)); - } - } - - if (x instanceof Complex) { - // acos(z) = 0.5*pi + i*log(iz + sqrt(1-z^2)) - var temp1 = Complex.create( - x.im * x.im - x.re * x.re + 1.0, - -2.0 * x.re * x.im - ); - var temp2 = math.sqrt(temp1); - var temp3; - if (temp2 instanceof Complex) { - temp3 = Complex.create( - temp2.re - x.im, - temp2.im + x.re - ) - } - else { - temp3 = Complex.create( - temp2 - x.im, - x.re - ) - } - var temp4 = math.log(temp3); - - // 0.5*pi = 1.5707963267948966192313216916398 - if (temp4 instanceof Complex) { - return Complex.create( - 1.57079632679489661923 - temp4.im, - temp4.re - ); - } - else { - return new Complex( - 1.57079632679489661923, - temp4 - ); - } - } - - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.acos); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.acos(x.valueOf()); - } - - throw newUnsupportedTypeError('acos', x); -}; - -/** - * Calculate the inverse sine of a value - * - * asin(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - * - * @see http://mathworld.wolfram.com/InverseSine.html - */ -math.asin = function asin(x) { - if (arguments.length != 1) { - throw newArgumentsError('asin', arguments.length, 1); - } - - if (isNumber(x)) { - if (x >= -1 && x <= 1) { - return Math.asin(x); - } - else { - return math.asin(new Complex(x, 0)); - } - } - - if (x instanceof Complex) { - // asin(z) = -i*log(iz + sqrt(1-z^2)) - var re = x.re; - var im = x.im; - var temp1 = Complex.create( - im * im - re * re + 1.0, - -2.0 * re * im - ); - - var temp2 = math.sqrt(temp1); - var temp3; - if (temp2 instanceof Complex) { - temp3 = Complex.create( - temp2.re - im, - temp2.im + re - ); - } - else { - temp3 = Complex.create( - temp2 - im, - re - ); - } - - var temp4 = math.log(temp3); - - if (temp4 instanceof Complex) { - return Complex.create(temp4.im, -temp4.re); - } - else { - return Complex.create(0, -temp4); - } - } - - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.asin); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.asin(x.valueOf()); - } - - throw newUnsupportedTypeError('asin', x); -}; - -/** - * Calculate the inverse tangent of a value - * - * atan(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - * - * @see http://mathworld.wolfram.com/InverseTangent.html - */ -math.atan = function atan(x) { - if (arguments.length != 1) { - throw newArgumentsError('atan', arguments.length, 1); - } - - if (isNumber(x)) { - return Math.atan(x); - } - - if (x instanceof Complex) { - // atan(z) = 1/2 * i * (ln(1-iz) - ln(1+iz)) - var re = x.re; - var im = x.im; - var den = re * re + (1.0 - im) * (1.0 - im); - - var temp1 = Complex.create( - (1.0 - im * im - re * re) / den, - (-2.0 * re) / den - ); - var temp2 = math.log(temp1); - - if (temp2 instanceof Complex) { - return Complex.create( - -0.5 * temp2.im, - 0.5 * temp2.re - ); - } - else { - return Complex.create( - 0, - 0.5 * temp2 - ); - } - } - - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.atan); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.atan(x.valueOf()); - } - - throw newUnsupportedTypeError('atan', x); -}; - -/** - * Computes the principal value of the arc tangent of y/x in radians - * - * atan2(y, x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} y - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - * - * @see http://mathworld.wolfram.com/InverseTangent.html - */ -math.atan2 = function atan2(y, x) { - if (arguments.length != 2) { - throw newArgumentsError('atan2', arguments.length, 2); - } - - if (isNumber(y)) { - if (isNumber(x)) { - return Math.atan2(y, x); - } - /* TODO: support for complex computation of atan2 - else if (x instanceof Complex) { - return Math.atan2(y.re, x.re); - } - */ - } - else if (y instanceof Complex) { - if (isNumber(x)) { - return Math.atan2(y.re, x); - } - /* TODO: support for complex computation of atan2 - else if (x instanceof Complex) { - return Math.atan2(y.re, x.re); - } - */ - } - - if (Array.isArray(y) || y instanceof Matrix || - Array.isArray(x) || x instanceof Matrix) { - return util.map2(y, x, math.atan2); - } - - if (x.valueOf() !== x || y.valueOf() !== y) { - // fallback on the objects primitive values - return math.atan2(y.valueOf(), x.valueOf()); - } - - throw newUnsupportedTypeError('atan2', y, x); -}; - -/** - * Calculate the cosine of a value - * - * cos(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Unit | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - * - * @see http://mathworld.wolfram.com/Cosine.html - */ -math.cos = function cos(x) { - if (arguments.length != 1) { - throw newArgumentsError('cos', arguments.length, 1); - } - - if (isNumber(x)) { - return Math.cos(x); - } - - if (x instanceof Complex) { - // cos(z) = (exp(iz) + exp(-iz)) / 2 - return Complex.create( - 0.5 * Math.cos(x.re) * (Math.exp(-x.im) + Math.exp(x.im)), - 0.5 * Math.sin(x.re) * (Math.exp(-x.im) - Math.exp(x.im)) - ); - } - - if (x instanceof Unit) { - if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function cos is no angle'); - } - return Math.cos(x.value); - } - - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.cos); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.cos(x.valueOf()); - } - - throw newUnsupportedTypeError('cos', x); -}; - -/** - * Calculate the cotangent of a value. cot(x) is defined as 1 / tan(x) - * - * cot(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Unit | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ -math.cot = function cot(x) { - if (arguments.length != 1) { - throw newArgumentsError('cot', arguments.length, 1); - } - - if (isNumber(x)) { - return 1 / Math.tan(x); - } - - if (x instanceof Complex) { - var den = Math.exp(-4.0 * x.im) - - 2.0 * Math.exp(-2.0 * x.im) * Math.cos(2.0 * x.re) + 1.0; - - return Complex.create( - 2.0 * Math.exp(-2.0 * x.im) * Math.sin(2.0 * x.re) / den, - (Math.exp(-4.0 * x.im) - 1.0) / den - ); - } - - if (x instanceof Unit) { - if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function cot is no angle'); - } - return 1 / Math.tan(x.value); - } - - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.cot); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.cot(x.valueOf()); - } - - throw newUnsupportedTypeError('cot', x); -}; - -/** - * Calculate the cosecant of a value, csc(x) = 1/sin(x) - * - * csc(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Unit | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ -math.csc = function csc(x) { - if (arguments.length != 1) { - throw newArgumentsError('csc', arguments.length, 1); - } - - if (isNumber(x)) { - return 1 / Math.sin(x); - } - - if (x instanceof Complex) { - // csc(z) = 1/sin(z) = (2i) / (exp(iz) - exp(-iz)) - var den = 0.25 * (Math.exp(-2.0 * x.im) + Math.exp(2.0 * x.im)) - - 0.5 * Math.cos(2.0 * x.re); - - return Complex.create ( - 0.5 * Math.sin(x.re) * (Math.exp(-x.im) + Math.exp(x.im)) / den, - 0.5 * Math.cos(x.re) * (Math.exp(-x.im) - Math.exp(x.im)) / den - ); - } - - if (x instanceof Unit) { - if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function csc is no angle'); - } - return 1 / Math.sin(x.value); - } - - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.csc); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.csc(x.valueOf()); - } - - throw newUnsupportedTypeError('csc', x); -}; - -/** - * Calculate the secant of a value, sec(x) = 1/cos(x) - * - * sec(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Unit | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ -math.sec = function sec(x) { - if (arguments.length != 1) { - throw newArgumentsError('sec', arguments.length, 1); - } - - if (isNumber(x)) { - return 1 / Math.cos(x); - } - - if (x instanceof Complex) { - // sec(z) = 1/cos(z) = 2 / (exp(iz) + exp(-iz)) - var den = 0.25 * (Math.exp(-2.0 * x.im) + Math.exp(2.0 * x.im)) + - 0.5 * Math.cos(2.0 * x.re); - return Complex.create( - 0.5 * Math.cos(x.re) * (Math.exp(-x.im) + Math.exp( x.im)) / den, - 0.5 * Math.sin(x.re) * (Math.exp( x.im) - Math.exp(-x.im)) / den - ); - } - - if (x instanceof Unit) { - if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function sec is no angle'); - } - return 1 / Math.cos(x.value); - } - - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.sec); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.sec(x.valueOf()); - } - - throw newUnsupportedTypeError('sec', x); -}; - -/** - * Calculate the sine of a value - * - * sin(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Unit | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - * - * @see http://mathworld.wolfram.com/Sine.html - */ -math.sin = function sin(x) { - if (arguments.length != 1) { - throw newArgumentsError('sin', arguments.length, 1); - } - - if (isNumber(x)) { - return Math.sin(x); - } - - if (x instanceof Complex) { - return Complex.create( - 0.5 * Math.sin(x.re) * (Math.exp(-x.im) + Math.exp( x.im)), - 0.5 * Math.cos(x.re) * (Math.exp( x.im) - Math.exp(-x.im)) - ); - } - - if (x instanceof Unit) { - if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function cos is no angle'); - } - return Math.sin(x.value); - } - - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.sin); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.sin(x.valueOf()); - } - - throw newUnsupportedTypeError('sin', x); -}; - -/** - * Calculate the tangent of a value - * - * tan(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Unit | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - * - * @see http://mathworld.wolfram.com/Tangent.html - */ -math.tan = function tan(x) { - if (arguments.length != 1) { - throw newArgumentsError('tan', arguments.length, 1); - } - - if (isNumber(x)) { - return Math.tan(x); - } - - if (x instanceof Complex) { - var den = Math.exp(-4.0 * x.im) + - 2.0 * Math.exp(-2.0 * x.im) * Math.cos(2.0 * x.re) + - 1.0; - - return Complex.create( - 2.0 * Math.exp(-2.0 * x.im) * Math.sin(2.0 * x.re) / den, - (1.0 - Math.exp(-4.0 * x.im)) / den - ); - } - - if (x instanceof Unit) { - if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function tan is no angle'); - } - return Math.tan(x.value); - } - - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.tan); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.tan(x.valueOf()); - } - - throw newUnsupportedTypeError('tan', x); -}; - -/** - * Change the unit of a value. - * - * x in unit - * in(x, unit) - * - * For matrices, the function is evaluated element wise. - * - * @param {Unit | Array | Matrix} x - * @param {Unit | Array | Matrix} unit - * @return {Unit | Array | Matrix} res - */ -math['in'] = function unit_in(x, unit) { - if (arguments.length != 2) { - throw newArgumentsError('in', arguments.length, 2); - } - - if (x instanceof Unit) { - if (unit instanceof Unit || isString(unit)) { - return x['in'](unit); - } - } - - // TODO: add support for string, in that case, convert to unit - - if (Array.isArray(x) || x instanceof Matrix || - Array.isArray(unit) || unit instanceof Matrix) { - return util.map2(x, unit, math['in']); - } - - if (x.valueOf() !== x || unit.valueOf() !== unit) { - // fallback on the objects primitive value - return math['in'](x.valueOf(), unit.valueOf()); - } - - throw newUnsupportedTypeError('in', x, unit); -}; - -/** - * Clone an object - * - * clone(x) - * - * @param {*} x - * @return {*} clone - */ -math.clone = function clone(x) { - if (arguments.length != 1) { - throw newArgumentsError('clone', arguments.length, 1); - } - - if (x == null) { - // null or undefined - return x; - } - - if (typeof(x.clone) === 'function') { - return x.clone(); - } - - if (isNumber(x) || isString(x) || isBoolean(x)) { - return x; - } - - if (Array.isArray(x)) { - var c = math.clone; - return x.map(function (value) { - return c(value); - }); - } - - if (x instanceof Object) { - return util.mapObject(x, math.clone); - } - - throw newUnsupportedTypeError('clone', x); -}; - -/** - * Evaluate an expression. - * - * Syntax: - * - * math.eval(expr) - * math.eval(expr, scope) - * math.eval([expr1, expr2, expr3, ...]) - * math.eval([expr1, expr2, expr3, ...], scope) - * - * Example: - * - * math.eval('(2+3)/4'); // 1.25 - * math.eval('sqrt(3^2 + 4^2)'); // 5 - * math.eval('sqrt(-4)'); // 2i - * math.eval(['a=3', 'b=4', 'a*b']);, // [3, 4, 12] - * - * var scope = {a:3, b:4}; - * math.eval('a * b', scope); // 12 - * - * @param {String | String[] | Matrix} expr - * @param {math.expr.Scope | Object} [scope] - * @return {*} res - * @throws {Error} - */ -math.eval = function (expr, scope) { - if (arguments.length != 1 && arguments.length != 2) { - throw newArgumentsError('eval', arguments.length, 1, 2); - } - - // instantiate a scope - var evalScope; - if (scope) { - if (scope instanceof math.expr.Scope) { - evalScope = scope; - } - else { - evalScope = new math.expr.Scope(scope); - } - } - else { - evalScope = new math.expr.Scope(); - } - - if (isString(expr)) { - // evaluate a single expression - var node = math.parse(expr, evalScope); - return node.eval(); - } - else if (Array.isArray(expr) || expr instanceof Matrix) { - // evaluate an array or matrix with expressions - return util.map(expr, function (elem) { - var node = math.parse(elem, evalScope); - return node.eval(); - }); - } - else { - // oops - throw new TypeError('String or matrix expected'); - } -}; - -/** - * Format a value of any type into a string. Interpolate values into the string. - * Numbers are rounded off to a maximum number of 5 digits by default. - * Usage: - * math.format(value) - * math.format(template, object) - * - * Example usage: - * math.format(2/7); // '0.28571' - * math.format(new Complex(2, 3)); // '2 + 3i' - * math.format('Hello $name! The date is $date', { - * name: 'user', - * date: new Date().toISOString().substring(0, 10) - * }); // 'hello user! The date is 2013-03-23' - * - * @param {String} template - * @param {Object} values - * @return {String} str - */ -math.format = function format(template, values) { - var num = arguments.length; - if (num != 1 && num != 2) { - throw newArgumentsError('format', num, 1, 2); - } - - if (num == 1) { - // just format a value as string - var value = arguments[0]; - if (isNumber(value)) { - return util.formatNumber(value, math.options.precision); - } - - if (Array.isArray(value)) { - return util.formatArray(value); - } - - if (isString(value)) { - return '"' + value + '"'; - } - - if (value instanceof Object) { - return value.toString(); - } - - return String(value); - } - else { - if (!isString(template)) { - throw new TypeError('String expected as first parameter in function format'); - } - if (!(values instanceof Object)) { - throw new TypeError('Object expected as first parameter in function format'); - } - - // format values into a string - return template.replace(/\$([\w\.]+)/g, function (original, key) { - var keys = key.split('.'); - var value = values[keys.shift()]; - while (keys.length && value != undefined) { - var k = keys.shift(); - value = k ? value[k] : value + '.'; - } - return value != undefined ? value : original; - } - ); - } -}; - -/** - * Retrieve help on a function or data type. - * Help files are retrieved from the documentation in math.docs. - * @param {function | string | Object} search - * @return {Help} help - */ -math.help = function help(search) { - if (arguments.length != 1) { - throw new SyntaxError('Wrong number of arguments in function help ' + - '(' + arguments.length + ' provided, 1 expected)'); - } - - var text = null; - if ((search instanceof String) || (typeof(search) === 'string')) { - text = search; - } - else { - var prop; - for (prop in math) { - // search in functions and constants - if (math.hasOwnProperty(prop)) { - if (search === math[prop]) { - text = prop; - break; - } - } - } - - if (!text) { - // search data type - for (prop in math.type) { - if (math.type.hasOwnProperty(prop)) { - if (search === math.type[prop]) { - text = prop; - break; - } - } - } - } - } - - if (!text) { - throw new Error('Could not find search term "' + search + '"'); - } - else { - var doc = math.docs[text]; - if (!doc) { - throw new Error('No documentation found on "' + text + '"'); - } - return new Help(doc); - } -}; - -/** - * Import functions from an object or a file - * @param {function | String | Object} object - * @param {Object} [options] Available options: - * {Boolean} override - * If true, existing functions will be - * overwritten. False by default. - * {Boolean} wrap - * If true (default), the functions will - * be wrapped in a wrapper function which - * converts data types like Matrix to - * primitive data types like Array. - * The wrapper is needed when extending - * math.js with libraries which do not - * support the math.js data types. - */ -// TODO: return status information -math['import'] = function math_import(object, options) { - var name; - var opts = { - override: false, - wrap: true - }; - if (options && options instanceof Object) { - util.extend(opts, options); - } - - if (isString(object)) { - // a string with a filename - if (typeof (require) !== 'undefined') { - // load the file using require - var _module = require(object); - math['import'](_module); - } - else { - throw new Error('Cannot load file: require not available.'); - } - } - else if (isSupportedType(object)) { - // a single function - name = object.name; - if (name) { - if (opts.override || math[name] === undefined) { - _import(name, object, opts); - } - } - else { - throw new Error('Cannot import an unnamed function or object'); - } - } - else if (object instanceof Object) { - // a map with functions - for (name in object) { - if (object.hasOwnProperty(name)) { - var value = object[name]; - if (isSupportedType(value)) { - _import(name, value, opts); - } - else { - math['import'](value); - } - } - } - } -}; - -/** - * Add a property to the math namespace and create a chain proxy for it. - * @param {String} name - * @param {*} value - * @param {Object} options See import for a description of the options - * @private - */ -function _import(name, value, options) { - if (options.override || math[name] === undefined) { - // add to math namespace - if (options.wrap && typeof value === 'function') { - // create a wrapper around the function - math[name] = function () { - var args = []; - for (var i = 0, len = arguments.length; i < len; i++) { - args[i] = arguments[i].valueOf(); - } - return value.apply(math, args); - }; - } - else { - // just create a link to the function or value - math[name] = value; - } - - // create a proxy for the Selector - createSelectorProxy(name, value); - } - -} - -/** - * Check whether given object is a supported type - * @param object - * @return {Boolean} - * @private - */ -function isSupportedType(object) { - return (typeof object == 'function') || - isNumber(object) || isString(object) || - (object instanceof Complex) || (object instanceof Unit); - // TODO: add boolean? -} - -(function () { - /** - * Parse an expression. Returns a node tree, which can be evaluated by - * invoking node.eval(); - * - * Syntax: - * - * math.parse(expr) - * math.parse(expr, scope) - * math.parse([expr1, expr2, expr3, ...]) - * math.parse([expr1, expr2, expr3, ...], scope) - * - * Example: - * - * var node = math.parse('sqrt(3^2 + 4^2)'); - * node.eval(); // 5 - * - * var scope = {a:3, b:4} - * var node = math.parse('a * b', scope); // 12 - * node.eval(); // 12 - * scope.a = 5; - * node.eval(); // 20 - * - * var nodes = math.parse(['a = 3', 'b = 4', 'a * b']); - * nodes[2].eval(); // 12 - * - * @param {String | String[] | Matrix} expr - * @param {math.expr.Scope | Object} [scope] - * @return {Node | Node[]} node - * @throws {Error} - */ - math.parse = function (expr, scope) { - if (arguments.length != 1 && arguments.length != 2) { - throw newArgumentsError('parse', arguments.length, 1, 2); - } - - // instantiate a scope - var parseScope; - if (scope) { - if (scope instanceof math.expr.Scope) { - parseScope = scope; - } - else { - parseScope = new math.expr.Scope(scope); - } - } - else { - parseScope = new math.expr.Scope(); - } - - if (isString(expr)) { - // parse a single expression - expression = expr || ''; - return parse_start(parseScope); - } - else if (Array.isArray(expr) || expr instanceof Matrix) { - // parse an array or matrix with expressions - return util.map(expr, function (elem) { - expression = elem || ''; - return parse_start(parseScope); - }); - } - else { - // oops - throw new TypeError('String or matrix expected'); - } - }; - - // token types enumeration - var TOKENTYPE = { - NULL : 0, - DELIMITER : 1, - NUMBER : 2, - SYMBOL : 3, - UNKNOWN : 4 - }; - - // map with all delimiters - var DELIMITERS = { - ',': true, - '(': true, - ')': true, - '[': true, - ']': true, - '\"': true, - '\n': true, - ';': true, - - '+': true, - '-': true, - '*': true, - '.*': true, - '/': true, - './': true, - '%': true, - '^': true, - '.^': true, - '!': true, - '\'': true, - '=': true, - ':': true, - - '==': true, - '!=': true, - '<': true, - '>': true, - '<=': true, - '>=': true - }; - - var handlers = math.expr.node.handlers; - - var expression = ''; // current expression - var index = 0; // current index in expr - var c = ''; // current token character in expr - var token = ''; // current token - var token_type = TOKENTYPE.NULL; // type of the token - - /** - * Get the first character from the expression. - * The character is stored into the char c. If the end of the expression is - * reached, the function puts an empty string in c. - * @private - */ - function first() { - index = 0; - c = expression.charAt(0); - } - - /** - * Get the next character from the expression. - * The character is stored into the char c. If the end of the expression is - * reached, the function puts an empty string in c. - * @private - */ - function next() { - index++; - c = expression.charAt(index); - } - - /** - * Preview the next character from the expression. - * @return {String} cNext - * @private - */ - function nextPreview() { - return expression.charAt(index + 1); - } - - /** - * Get next token in the current string expr. - * The token and token type are available as token and token_type - * @private - */ - function getToken() { - token_type = TOKENTYPE.NULL; - token = ''; - - // skip over whitespaces - while (c == ' ' || c == '\t') { // space or tab - next(); - } - - // skip comment - if (c == '#') { - while (c != '\n' && c != '') { - next(); - } - } - - // check for end of expression - if (c == '') { - // token is still empty - token_type = TOKENTYPE.DELIMITER; - return; - } - - // check for delimiters consisting of 2 characters - var c2 = c + nextPreview(); - if (DELIMITERS[c2]) { - token_type = TOKENTYPE.DELIMITER; - token = c2; - next(); - next(); - return; - } - - // check for delimiters consisting of 1 character - if (DELIMITERS[c]) { - token_type = TOKENTYPE.DELIMITER; - token = c; - next(); - return; - } - - // check for a number - if (isDigitDot(c)) { - token_type = TOKENTYPE.NUMBER; - - // get number, can have a single dot - if (c == '.') { - token += c; - next(); - - if (!isDigit(c)) { - // this is no legal number, it is just a dot - token_type = TOKENTYPE.UNKNOWN; - } - } - else { - while (isDigit(c)) { - token += c; - next(); - } - if (c == '.') { - token += c; - next(); - } - } - while (isDigit(c)) { - token += c; - next(); - } - - // check for scientific notation like "2.3e-4" or "1.23e50" - if (c == 'E' || c == 'e') { - token += c; - next(); - - if (c == '+' || c == '-') { - token += c; - next(); - } - - // Scientific notation MUST be followed by an exponent - if (!isDigit(c)) { - // this is no legal number, exponent is missing. - token_type = TOKENTYPE.UNKNOWN; - } - - while (isDigit(c)) { - token += c; - next(); - } - } - - return; - } - - // check for variables or functions - if (isAlpha(c)) { - token_type = TOKENTYPE.SYMBOL; - - while (isAlpha(c) || isDigit(c)) { - token += c; - next(); - } - return; - } - - // something unknown is found, wrong characters -> a syntax error - token_type = TOKENTYPE.UNKNOWN; - while (c != '') { - token += c; - next(); - } - throw createSyntaxError('Syntax error in part "' + token + '"'); - } - - /** - * Check if a given name is valid - * if not, an error is thrown - * @param {String} name - * @return {boolean} valid - * @private - */ - // TODO: check for valid symbol name - function isValidSymbolName (name) { - for (var i = 0, iMax = name.length; i < iMax; i++) { - var c = name.charAt(i); - //var valid = (isAlpha(c) || (i > 0 && isDigit(c))); // TODO: allow digits in symbol name - var valid = (isAlpha(c)); - if (!valid) { - return false; - } - } - - return true; - } - - /** - * checks if the given char c is a letter (upper or lower case) - * or underscore - * @param {String} c a string with one character - * @return {Boolean} - * @private - */ - function isAlpha (c) { - return ((c >= 'a' && c <= 'z') || - (c >= 'A' && c <= 'Z') || - c == '_'); - } - - /** - * checks if the given char c is a digit or dot - * @param {String} c a string with one character - * @return {Boolean} - * @private - */ - function isDigitDot (c) { - return ((c >= '0' && c <= '9') || - c == '.'); - } - - /** - * checks if the given char c is a digit - * @param {String} c a string with one character - * @return {Boolean} - * @private - */ - function isDigit (c) { - return ((c >= '0' && c <= '9')); - } - - /** - * Start of the parse levels below, in order of precedence - * @param {math.expr.Scope} scope - * @return {Node} node - * @private - */ - function parse_start (scope) { - // get the first character in expression - first(); - - getToken(); - - var node; - if (token == '') { - // empty expression - node = new ConstantNode(undefined); - } - else { - node = parse_block(scope); - } - - // check for garbage at the end of the expression - // an expression ends with a empty character '' and token_type DELIMITER - if (token != '') { - if (token_type == TOKENTYPE.DELIMITER) { - // user entered a not existing operator like "//" - - // TODO: give hints for aliases, for example with "<>" give as hint " did you mean != ?" - throw createError('Unknown operator ' + token); - } - else { - throw createSyntaxError('Unexpected part "' + token + '"'); - } - } - - return node; - } - - /** - * Parse a block with expressions. Expressions can be separated by a newline - * character '\n', or by a semicolon ';'. In case of a semicolon, no output - * of the preceding line is returned. - * @param {math.expr.Scope} scope - * @return {Node} node - * @private - */ - function parse_block (scope) { - var node, block, visible; - - if (token != '\n' && token != ';' && token != '') { - node = parse_ans(scope); - } - - while (token == '\n' || token == ';') { - if (!block) { - // initialize the block - block = new BlockNode(); - if (node) { - visible = (token != ';'); - block.add(node, visible); - } - } - - getToken(); - if (token != '\n' && token != ';' && token != '') { - node = parse_ans(scope); - - visible = (token != ';'); - block.add(node, visible); - } - } - - if (block) { - return block; - } - - if (!node) { - node = parse_ans(scope); - } - - return node; - } - - /** - * Parse assignment of ans. - * Ans is assigned when the expression itself is no variable or function - * assignment - * @param {math.expr.Scope} scope - * @return {Node} node - * @private - */ - function parse_ans (scope) { - var expression = parse_function_assignment(scope); - - // create a variable definition for ans - var name = 'ans'; - return new AssignmentNode(name, expression, scope); - } - - /** - * Parse a function assignment like "function f(a,b) = a*b" - * @param {math.expr.Scope} scope - * @return {Node} node - * @private - */ - function parse_function_assignment (scope) { - // TODO: keyword 'function' must become a reserved keyword - // TODO: replace the 'function' keyword with an assignment operator '=>' - if (token_type == TOKENTYPE.SYMBOL && token == 'function') { - // get function name - getToken(); - if (token_type != TOKENTYPE.SYMBOL) { - throw createSyntaxError('Function name expected'); - } - var name = token; - - // get parenthesis open - getToken(); - if (token != '(') { - throw createSyntaxError('Opening parenthesis ( expected'); - } - - // get function variables - var functionScope = scope.createSubScope(); - var variables = []; - while (true) { - getToken(); - if (token_type == TOKENTYPE.SYMBOL) { - // store variable name - variables.push(token); - } - else { - throw createSyntaxError('Variable name expected'); - } - - getToken(); - if (token == ',') { - // ok, nothing to do, read next variable - } - else if (token == ')') { - // end of variable list encountered. break loop - break; - } - else { - throw createSyntaxError('Comma , or closing parenthesis ) expected"'); - } - } - - getToken(); - if (token != '=') { - throw createSyntaxError('Equal sign = expected'); - } - - // parse the expression, with the correct function scope - getToken(); - var expression = parse_assignment(functionScope); - - return new FunctionNode(name, variables, expression, functionScope, scope); - } - - return parse_assignment(scope); - } - - /** - * Assignment of a variable, can be a variable like "a=2.3" or a updating an - * existing variable like "matrix(2,3:5)=[6,7,8]" - * @param {math.expr.Scope} scope - * @return {Node} node - * @private - */ - function parse_assignment (scope) { - var name, params, paramScopes, expr; - - var node = parse_range(scope); - - if (token == '=') { - if (node instanceof SymbolNode) { - // parse the expression, with the correct function scope - getToken(); - name = node.name; - params = null; - expr = parse_assignment(scope); - return new AssignmentNode(name, expr, scope); - } - else if (node instanceof ParamsNode && node.object instanceof SymbolNode) { - // parse the expression, with the correct function scope - getToken(); - name = node.object.name; - params = node.params; - paramScopes = node.paramScopes; - expr = parse_assignment(scope); - return new UpdateNode(name, params, paramScopes, expr, scope); - } - else { - throw createSyntaxError('Symbol expected at the left hand side ' + - 'of assignment operator ='); - } - } - - return node; - } - - /** - * parse range, "start:end", "start:step:end", ":", "start:", ":end", etc - * @param {math.expr.Scope} scope - * @return {Node} node - * @private - */ - function parse_range (scope) { - var node, name, fn, params = []; - - if (token == ':') { - // implicit start=0 - node = new ConstantNode(0); - } - else { - // explicit start - node = parse_conditions(scope); - } - - if (token == ':') { - params.push(node); - - // parse step and end - while (token == ':') { - getToken(); - if (token == ')' || token == ',' || token == '') { - // implicit end - params.push(new SymbolNode('end', scope)); - } - else { - // explicit end - params.push(parse_conditions(scope)); - } - } - - if (params.length) { - // create a range constructor - name = 'range'; - fn = math.range; - node = new OperatorNode(name, fn, params); - } - } - - return node; - } - - /** - * conditions like and, or, in - * @param {math.expr.Scope} scope - * @return {Node} node - * @private - */ - function parse_conditions (scope) { - var node, operators, name, fn, params; - - node = parse_bitwise_conditions(scope); - - // TODO: precedence of And above Or? - // TODO: implement a method for unit to number conversion - operators = { - 'in' : 'in' - /* TODO: implement conditions - 'and' : 'and', - '&&' : 'and', - 'or': 'or', - '||': 'or', - 'xor': 'xor' - */ - }; - - while (operators[token] !== undefined) { - name = token; - fn = math[operators[name]]; - - getToken(); - params = [node, parse_bitwise_conditions(scope)]; - node = new OperatorNode(name, fn, params); - } - - return node; - } - - /** - * conditional operators and bitshift - * @param {math.expr.Scope} scope - * @return {Node} node - * @private - */ - function parse_bitwise_conditions (scope) { - var node = parse_comparison(scope); - - /* TODO: implement bitwise conditions - var operators = { - '&' : 'bitwiseand', - '|' : 'bitwiseor', - // todo: bitwise xor? - '<<': 'bitshiftleft', - '>>': 'bitshiftright' - }; - while (operators[token] !== undefined) { - var name = token; - var fn = math[operators[name]]; - - getToken(); - var params = [node, parse_comparison()]; - node = new OperatorNode(name, fn, params); - } - */ - - return node; - } - - /** - * comparison operators - * @param {math.expr.Scope} scope - * @return {Node} node - * @private - */ - function parse_comparison (scope) { - var node, operators, name, fn, params; - - node = parse_addsubtract(scope); - - operators = { - '==': 'equal', - '!=': 'unequal', - '<': 'smaller', - '>': 'larger', - '<=': 'smallereq', - '>=': 'largereq' - }; - while (operators[token] !== undefined) { - name = token; - fn = math[operators[name]]; - - getToken(); - params = [node, parse_addsubtract(scope)]; - node = new OperatorNode(name, fn, params); - } - - return node; - } - - /** - * add or subtract - * @param {math.expr.Scope} scope - * @return {Node} node - * @private - */ - function parse_addsubtract (scope) { - var node, operators, name, fn, params; - - node = parse_multiplydivide(scope); - - operators = { - '+': 'add', - '-': 'subtract' - }; - while (operators[token] !== undefined) { - name = token; - fn = math[operators[name]]; - - getToken(); - params = [node, parse_multiplydivide(scope)]; - node = new OperatorNode(name, fn, params); - } - - return node; - } - - /** - * multiply, divide, modulus - * @param {math.expr.Scope} scope - * @return {Node} node - * @private - */ - function parse_multiplydivide (scope) { - var node, operators, name, fn, params; - - node = parse_unary(scope); - - operators = { - '*': 'multiply', - '.*': 'emultiply', - '/': 'divide', - './': 'edivide', - '%': 'mod', - 'mod': 'mod' - }; - - while (operators[token] !== undefined) { - name = token; - fn = math[operators[name]]; - - getToken(); - params = [node, parse_unary(scope)]; - node = new OperatorNode(name, fn, params); - } - - return node; - } - - /** - * Unary minus - * @param {math.expr.Scope} scope - * @return {Node} node - * @private - */ - function parse_unary (scope) { - var name, fn, params; - - if (token == '-') { - name = token; - fn = math.unary; - getToken(); - params = [parse_unary(scope)]; - - return new OperatorNode(name, fn, params); - } - - return parse_pow(scope); - } - - /** - * power - * Node: power operator is right associative - * @param {math.expr.Scope} scope - * @return {Node} node - * @private - */ - function parse_pow (scope) { - var node, leftNode, nodes, ops, name, fn, params; - - nodes = [ - parse_factorial(scope) - ]; - ops = []; - - // stack all operands of a chained power operator (like '2^3^3') - while (token == '^' || token == '.^') { - ops.push(token); - getToken(); - nodes.push(parse_factorial(scope)); - } - - // evaluate the operands from right to left (right associative) - node = nodes.pop(); - while (nodes.length) { - leftNode = nodes.pop(); - name = ops.pop(); - fn = (name == '^') ? math.pow : math.epow; - params = [leftNode, node]; - node = new OperatorNode(name, fn, params); - } - - return node; - } - - /** - * Factorial - * @param {math.expr.Scope} scope - * @return {Node} node - * @private - */ - function parse_factorial (scope) { - var node, name, fn, params; - - node = parse_transpose(scope); - - while (token == '!') { - name = token; - fn = math.factorial; - getToken(); - params = [node]; - - node = new OperatorNode(name, fn, params); - } - - return node; - } - - /** - * Transpose - * @param {math.expr.Scope} scope - * @return {Node} node - * @private - */ - function parse_transpose (scope) { - var node, name, fn, params; - - node = parse_node_handler(scope); - - while (token == '\'') { - name = token; - fn = math.transpose; - getToken(); - params = [node]; - - node = new OperatorNode(name, fn, params); - } - - return node; - } - - /** - * Parse a custom node handler. A node handler can be used to process - * nodes in a custom way, for example for handling a plot. - * - * A handler must be defined in the namespace math.expr.node.handlers, - * and must extend math.expr.node.Node, and the handler must contain - * functions eval(), find(filter), and toString(). - * - * For example: - * - * math.expr.node.handlers['plot'] = PlotHandler; - * - * The constructor of the handler is called as: - * - * node = new PlotHandler(params, paramScopes); - * - * The handler will be invoked when evaluating an expression like: - * - * node = math.parse('plot(sin(x), x)'); - * - * @param {math.expr.Scope} scope - * @return {Node} node - * @private - */ - function parse_node_handler (scope) { - var params, - paramScopes, - paramScope, - handler; - - if (token_type == TOKENTYPE.SYMBOL && handlers[token]) { - handler = handlers[token]; - - getToken(); - - // parse parameters - if (token == '(') { - params = []; - paramScopes = []; - - getToken(); - - if (token != ')') { - paramScope = scope.createSubScope(); - paramScopes.push(paramScope); - params.push(parse_range(paramScope)); - - // parse a list with parameters - while (token == ',') { - getToken(); - - paramScope = scope.createSubScope(); - paramScopes.push(paramScope); - params.push(parse_range(paramScope)); - } - } - - if (token != ')') { - throw createSyntaxError('Parenthesis ) expected'); - } - getToken(); - } - - // create a new node handler - //noinspection JSValidateTypes - return new handler(params, paramScopes); - } - - return parse_symbol(scope); - } - - /** - * parse symbols: functions, variables, constants, units - * @param {math.expr.Scope} scope - * @return {Node} node - * @private - */ - function parse_symbol (scope) { - var node, name; - - if (token_type == TOKENTYPE.SYMBOL) { - name = token; - - getToken(); - - // create a symbol - node = new SymbolNode(name, scope); - - // parse parameters - return parse_params(scope, node); - } - - return parse_string(scope); - } - - /** - * parse parameters, enclosed in parenthesis - * @param {math.expr.Scope} scope - * @param {Node} node Node on which to apply the parameters. If there - * are no parameters in the expression, the node - * itself is returned - * @return {Node} node - * @private - */ - function parse_params (scope, node) { - var params, - paramScopes, - paramScope; - - while (token == '(') { - params = []; - paramScopes = []; - - getToken(); - - if (token != ')') { - paramScope = scope.createSubScope(); - paramScopes.push(paramScope); - params.push(parse_range(paramScope)); - - // parse a list with parameters - while (token == ',') { - getToken(); - - paramScope = scope.createSubScope(); - paramScopes.push(paramScope); - params.push(parse_range(paramScope)); - } - } - - if (token != ')') { - throw createSyntaxError('Parenthesis ) expected'); - } - getToken(); - - node = new ParamsNode(node, params, paramScopes); - } - - return node; - } - - /** - * parse a string. - * A string is enclosed by double quotes - * @param {math.expr.Scope} scope - * @return {Node} node - * @private - */ - function parse_string (scope) { - var node, str, tPrev; - - if (token == '"') { - // string "..." - str = ''; - tPrev = ''; - while (c != '' && (c != '\"' || tPrev == '\\')) { // also handle escape character - str += c; - tPrev = c; - next(); - } - - getToken(); - if (token != '"') { - throw createSyntaxError('End of string " expected'); - } - getToken(); - - // create constant - node = new ConstantNode(str); - - // parse parameters - node = parse_params(scope, node); - - return node; - } - - return parse_matrix(scope); - } - - /** - * parse the matrix - * @param {math.expr.Scope} scope - * @return {Node} A MatrixNode - * @private - */ - function parse_matrix (scope) { - var array, params, r, c, rows, cols; - - if (token == '[') { - // matrix [...] - - // skip newlines - getToken(); - while (token == '\n') { - getToken(); - } - - // check if this is an empty matrix "[ ]" - if (token != ']') { - // this is a non-empty matrix - params = []; - r = 0; - c = 0; - - params[0] = [parse_assignment(scope)]; - - // the columns in the matrix are separated by commas, and the rows by dot-comma's - while (token == ',' || token == ';') { - if (token == ',') { - c++; - } - else { - r++; - c = 0; - params[r] = []; - } - - // skip newlines - getToken(); - while (token == '\n') { - getToken(); - } - - params[r][c] = parse_assignment(scope); - - // skip newlines - while (token == '\n') { - getToken(); - } - } - - // TODO: spaces as separator for matrix columns - /* - // the columns in the matrix are separated by commas or spaces, - // and the rows by dot-comma's - while (token && token != ']') { - if (token == ';') { - r++; - c = 0; - params[r] = []; - getToken(); - } - else if (token == ',') { - c++; - getToken(); - } - else { - c++; - } - - // skip newlines - while (token == '\n') { - getToken(); - } - - //TODO: math.eval('[1 -2 3]') is evaluated as '[(1-2) 3]' instead of '[(1) (-2) (3)]' - //TODO: '[(1) (-2) (3)]' doesn't work - params[r][c] = parse_assignment(scope); - - // skip newlines - while (token == '\n') { - getToken(); - } - } - */ - - rows = params.length; - cols = (params.length > 0) ? params[0].length : 0; - - // check if the number of columns matches in all rows - for (r = 1; r < rows; r++) { - if (params[r].length != cols) { - throw createError('Number of columns must match ' + - '(' + params[r].length + ' != ' + cols + ')'); - } - } - - if (token != ']') { - throw createSyntaxError('End of matrix ] expected'); - } - - getToken(); - array = new MatrixNode(params); - } - else { - // this is an empty matrix "[ ]" - getToken(); - array = new MatrixNode([[]]); - } - - // parse parameters - array = parse_params(scope, array); - - return array; - } - - return parse_number(scope); - } - - /** - * parse a number - * @param {math.expr.Scope} scope - * @return {Node} node - * @private - */ - function parse_number (scope) { - var node, value, number; - - if (token_type == TOKENTYPE.NUMBER) { - // this is a number - if (token == '.') { - number = 0; - } else { - number = Number(token); - } - getToken(); - - /* TODO: implicit multiplication? - // TODO: how to calculate a=3; 2/2a ? is this (2/2)*a or 2/(2*a) ? - // check for implicit multiplication - if (token_type == TOKENTYPE.VARIABLE) { - node = multiply(node, parse_pow()); - } - //*/ - - if (token_type == TOKENTYPE.SYMBOL) { - if (token == 'i' || token == 'I') { - value = new Complex(0, number); - getToken(); - return new ConstantNode(value); - } - - if (Unit.isPlainUnit(token)) { - value = new Unit(number, token); - getToken(); - return new ConstantNode(value); - } - - throw createTypeError('Unknown unit "' + token + '"'); - } - - // just a regular number - node = new ConstantNode(number); - - // parse parameters - node = parse_params(scope, node); - - return node; - } - - return parse_parentheses(scope); - } - - /** - * parentheses - * @param {math.expr.Scope} scope - * @return {Node} node - * @private - */ - function parse_parentheses (scope) { - var node; - - // check if it is a parenthesized expression - if (token == '(') { - // parentheses (...) - getToken(); - node = parse_assignment(scope); // start again - - if (token != ')') { - throw createSyntaxError('Parenthesis ) expected'); - } - getToken(); - - /* TODO: implicit multiplication? - // TODO: how to calculate a=3; 2/2a ? is this (2/2)*a or 2/(2*a) ? - // check for implicit multiplication - if (token_type == TOKENTYPE.VARIABLE) { - node = multiply(node, parse_pow()); - } - //*/ - - // parse parameters - node = parse_params(scope, node); - - return node; - } - - return parse_end(scope); - } - - /** - * Evaluated when the expression is not yet ended but expected to end - * @param {math.expr.Scope} scope - * @return {Node} res - * @private - */ - function parse_end (scope) { - if (token == '') { - // syntax error or unexpected end of expression - throw createSyntaxError('Unexpected end of expression'); - } else { - throw createSyntaxError('Value expected'); - } - } - - /** - * Shortcut for getting the current row value (one based) - * Returns the line of the currently handled expression - * @private - */ - function row () { - // TODO: also register row number during parsing - return undefined; - } - - /** - * Shortcut for getting the current col value (one based) - * Returns the column (position) where the last token starts - * @private - */ - function col () { - return index - token.length + 1; - } - - /** - * Build up an error message - * @param {String} message - * @return {String} message with row and column information - * @private - */ - function createErrorMessage (message) { - var r = row(); - var c = col(); - if (r === undefined) { - if (c === undefined) { - return message; - } else { - return message + ' (char ' + c + ')'; - } - } else { - return message + ' (line ' + r + ', char ' + c + ')'; - } - } - - /** - * Create an error - * @param {String} message - * @return {SyntaxError} instantiated error - * @private - */ - function createSyntaxError (message) { - return new SyntaxError(createErrorMessage(message)); - } - - /** - * Create an error - * @param {String} message - * @return {TypeError} instantiated error - * @private - */ - function createTypeError(message) { - return new TypeError(createErrorMessage(message)); - } - - /** - * Create an error - * @param {String} message - * @return {Error} instantiated error - * @private - */ - function createError (message) { - return new Error(createErrorMessage(message)); - } - -})(); - -/** - * Wrap any value in a Selector, allowing to perform chained operations on - * the value. - * - * All methods available in the math.js library can be called upon the selector, - * and then will be evaluated with the value itself as first argument. - * The selector can be closed by executing selector.done(), which will return - * the final value. - * - * Example usage: - * math.select(3) - * .add(4) - * .subtract(2) - * .done(); // 5 - * math.select( [[1, 2], [3, 4]] ) - * .set([1, 1], 8) - * .multiply(3) - * .done(); // [[24, 6], [9, 12]] - * - * The Selector has a number of special functions: - * - done() Finalize the chained operation and return the selectors value. - * - valueOf() The same as done() - * - toString() Executes math.format() onto the selectors value, returning - * a string representation of the value. - * - get(...) Get a subselection of the selectors value. Only applicable when - * the value has a method get, for example when value is a Matrix - * or Array. - * - set(...) Replace a subselection of the selectors value. Only applicable - * when the value has a method get, for example when value is a - * Matrix or Array. - * - * @param {*} value - * @return {math.type.Selector} selector - */ -math.select = function select(value) { - return new math.type.Selector(value); -}; - -/** - * Determine the type of a variable - * - * typeof(x) - * - * @param {*} x - * @return {String} type Lower case type, for example "number", "string", - * "array". - */ -math['typeof'] = function math_typeof(x) { - if (arguments.length != 1) { - throw newArgumentsError('typeof', arguments.length, 1); - } - - var type = typeof x, - name; - - if (type == 'object') { - if (x == null) { - return 'null'; - } - if (x instanceof Boolean) { - return 'boolean'; - } - if (x instanceof Number) { - return 'number'; - } - if (x instanceof String) { - return 'string'; - } - if (Array.isArray(x)) { - return 'array'; - } - if (x instanceof Date) { - return 'date'; - } - if (x.constructor) { - // search functions / constants - for (name in math) { - if (math.hasOwnProperty(name)) { - if (x.constructor == math[name]) { - return name.toLowerCase(); - } - } - } - - // search data types - for (name in math.type) { - if (math.type.hasOwnProperty(name)) { - if (x.constructor == math.type[name]) { - return name.toLowerCase(); - } - } - } - - // try the constructors name as last resort - if (x.constructor.name) { - return x.constructor.name.toLowerCase(); - } - } - } - - return type; -}; - -math.docs['Infinity'] = { - 'name': 'Infinity', - 'category': 'Constants', - 'syntax': [ - 'Infinity' - ], - 'description': 'Infinity, a number which is larger than the maximum number that can be handled by a floating point number.', - 'examples': [ - 'Infinity', - '1 / 0' - ], - 'seealso': [] -}; - -math.docs.LN10 = { - 'name': 'LN10', - 'category': 'Constants', - 'syntax': [ - 'LN10' - ], - 'description': 'Returns the natural logarithm of 10, approximately equal to 2.302', - 'examples': [ - 'LN10', - 'log(10)' - ], - 'seealso': [] -}; - -math.docs.LN2 = { - 'name': 'LN2', - 'category': 'Constants', - 'syntax': [ - 'LN2' - ], - 'description': 'Returns the natural logarithm of 2, approximately equal to 0.693', - 'examples': [ - 'LN2', - 'log(2)' - ], - 'seealso': [] -}; - -math.docs.LOG10E = { - 'name': 'LOG10E', - 'category': 'Constants', - 'syntax': [ - 'LOG10E' - ], - 'description': 'Returns the base-10 logarithm of E, approximately equal to 0.434', - 'examples': [ - 'LOG10E', - 'log(e, 10)' - ], - 'seealso': [] -}; - -math.docs.LOG2E = { - 'name': 'LOG2E', - 'category': 'Constants', - 'syntax': [ - 'LOG2E' - ], - 'description': 'Returns the base-2 logarithm of E, approximately equal to 1.442', - 'examples': [ - 'LOG2E', - 'log(e, 2)' - ], - 'seealso': [] -}; - -math.docs['NaN'] = { - 'name': 'NaN', - 'category': 'Constants', - 'syntax': [ - 'NaN' - ], - 'description': 'Not a number', - 'examples': [ - 'NaN', - '0 / 0' - ], - 'seealso': [] -}; - -math.docs.SQRT1_2 = { - 'name': 'SQRT1_2', - 'category': 'Constants', - 'syntax': [ - 'SQRT1_2' - ], - 'description': 'Returns the square root of 1/2, approximately equal to 0.707', - 'examples': [ - 'SQRT1_2', - 'sqrt(1/2)' - ], - 'seealso': [] -}; - -math.docs.SQRT2 = { - 'name': 'SQRT2', - 'category': 'Constants', - 'syntax': [ - 'SQRT2' - ], - 'description': 'Returns the square root of 2, approximately equal to 1.414', - 'examples': [ - 'SQRT2', - 'sqrt(2)' - ], - 'seealso': [] -}; - -math.docs.e = math.docs.E = { - 'name': 'e', - 'category': 'Constants', - 'syntax': [ - 'e' - ], - 'description': 'Euler\'s number, the base of the natural logarithm. Approximately equal to 2.71828', - 'examples': [ - 'e', - 'e ^ 2', - 'exp(2)', - 'log(e)' - ], - 'seealso': ['exp'] -}; - -math.docs['false'] = { - 'name': 'false', - 'category': 'Constants', - 'syntax': [ - 'false' - ], - 'description': 'Boolean value false', - 'examples': [ - 'false' - ], - 'seealso': ['true'] -}; - -math.docs.i = { - 'name': 'i', - 'category': 'Constants', - 'syntax': [ - 'i' - ], - 'description': 'Imaginary unit, defined as i*i=-1. A complex number is described as a + b*i, where a is the real part, and b is the imaginary part.', - 'examples': [ - 'i', - 'i * i', - 'sqrt(-1)' - ], - 'seealso': [] -}; - -math.docs.pi = math.docs.PI = { - 'name': 'pi', - 'category': 'Constants', - 'syntax': [ - 'pi' - ], - 'description': 'The number pi is a mathematical constant that is the ratio of a circle\'s circumference to its diameter, and is approximately equal to 3.14159', - 'examples': [ - 'pi', - 'sin(pi/2)' - ], - 'seealso': ['tau'] -}; - -math.docs.tau = { - 'name': 'tau', - 'category': 'Constants', - 'syntax': [ - 'pi' - ], - 'description': 'Tau is the ratio constant of a circle\'s circumference to radius, equal to 2 * pi, approximately 6.2832.', - 'examples': [ - 'tau', - '2 * pi' - ], - 'seealso': ['pi'] -}; - -math.docs['true'] = { - 'name': 'true', - 'category': 'Constants', - 'syntax': [ - 'true' - ], - 'description': 'Boolean value true', - 'examples': [ - 'true' - ], - 'seealso': ['false'] -}; - -math.docs.abs = { - 'name': 'abs', - 'category': 'Arithmetic', - 'syntax': [ - 'abs(x)' - ], - 'description': 'Compute the absolute value.', - 'examples': [ - 'abs(3.5)', - 'abs(-4.2)' - ], - 'seealso': ['sign'] -}; - -math.docs.add = { - 'name': 'add', - 'category': 'Operators', - 'syntax': [ - 'x + y', - 'add(x, y)' - ], - 'description': 'Add two values.', - 'examples': [ - '2.1 + 3.6', - 'ans - 3.6', - '3 + 2i', - '"hello" + " world"', - '3 cm + 2 inch' - ], - 'seealso': [ - 'subtract' - ] -}; - -math.docs.ceil = { - 'name': 'ceil', - 'category': 'Arithmetic', - 'syntax': [ - 'ceil(x)' - ], - 'description': - 'Round a value towards plus infinity.If x is complex, both real and imaginary part are rounded towards plus infinity.', - 'examples': [ - 'ceil(3.2)', - 'ceil(3.8)', - 'ceil(-4.2)' - ], - 'seealso': ['floor', 'fix', 'round'] -}; - -math.docs.cube = { - 'name': 'cube', - 'category': 'Arithmetic', - 'syntax': [ - 'cube(x)' - ], - 'description': 'Compute the cube of a value. The cube of x is x * x * x.', - 'examples': [ - 'cube(2)', - '2^3', - '2 * 2 * 2' - ], - 'seealso': [ - 'multiply', - 'square', - 'pow' - ] -}; - -math.docs.divide = { - 'name': 'divide', - 'category': 'Operators', - 'syntax': [ - 'x / y', - 'divide(x, y)' - ], - 'description': 'Divide two values.', - 'examples': [ - '2 / 3', - 'ans * 3', - '4.5 / 2', - '3 + 4 / 2', - '(3 + 4) / 2', - '18 km / 4.5' - ], - 'seealso': [ - 'multiply' - ] -}; - -math.docs.edivide = { - 'name': 'edivide', - 'category': 'Operators', - 'syntax': [ - 'x ./ y', - 'edivide(x, y)' - ], - 'description': 'divide two values element wise.', - 'examples': [ - 'a = [1, 2, 3; 4, 5, 6]', - 'b = [2, 1, 1; 3, 2, 5]', - 'a ./ b' - ], - 'seealso': [ - 'multiply', - 'emultiply', - 'divide' - ] -}; - -math.docs.emultiply = { - 'name': 'emultiply', - 'category': 'Operators', - 'syntax': [ - 'x .* y', - 'emultiply(x, y)' - ], - 'description': 'multiply two values element wise.', - 'examples': [ - 'a = [1, 2, 3; 4, 5, 6]', - 'b = [2, 1, 1; 3, 2, 5]', - 'a .* b' - ], - 'seealso': [ - 'multiply', - 'divide', - 'edivide' - ] -}; - -math.docs.epow = { - 'name': 'epow', - 'category': 'Operators', - 'syntax': [ - 'x .^ y', - 'epow(x, y)' - ], - 'description': - 'Calculates the power of x to y element wise.', - 'examples': [ - 'a = [1, 2, 3; 4, 5, 6]', - 'a .^ 2' - ], - 'seealso': [ - 'pow' - ] -}; - -math.docs.equal = { - 'name': 'equal', - 'category': 'Operators', - 'syntax': [ - 'x == y', - 'equal(x, y)' - ], - 'description': - 'Check equality of two values. Returns 1 if the values are equal, and 0 if not.', - 'examples': [ - '2+2 == 3', - '2+2 == 4', - 'a = 3.2', - 'b = 6-2.8', - 'a == b', - '50cm == 0.5m' - ], - 'seealso': [ - 'unequal', 'smaller', 'larger', 'smallereq', 'largereq' - ] -}; - -math.docs.exp = { - 'name': 'exp', - 'category': 'Arithmetic', - 'syntax': [ - 'exp(x)' - ], - 'description': 'Calculate the exponent of a value.', - 'examples': [ - 'exp(1.3)', - 'e ^ 1.3', - 'log(exp(1.3))', - 'x = 2.4', - '(exp(i*x) == cos(x) + i*sin(x)) # Euler\'s formula' - ], - 'seealso': [ - 'square', - 'multiply', - 'log' - ] -}; - -math.docs.fix = { - 'name': 'fix', - 'category': 'Arithmetic', - 'syntax': [ - 'fix(x)' - ], - 'description': - 'Round a value towards zero.If x is complex, both real and imaginary part are rounded towards zero.', - 'examples': [ - 'fix(3.2)', - 'fix(3.8)', - 'fix(-4.2)', - 'fix(-4.8)' - ], - 'seealso': ['ceil', 'floor', 'round'] -}; - -math.docs.floor = { - 'name': 'floor', - 'category': 'Arithmetic', - 'syntax': [ - 'floor(x)' - ], - 'description': - 'Round a value towards minus infinity.If x is complex, both real and imaginary part are rounded towards minus infinity.', - 'examples': [ - 'floor(3.2)', - 'floor(3.8)', - 'floor(-4.2)' - ], - 'seealso': ['ceil', 'fix', 'round'] -}; - -math.docs.gcd = { - 'name': 'gcd', - 'category': 'Arithmetic', - 'syntax': [ - 'gcd(a, b)', - 'gcd(a, b, c, ...)' - ], - 'description': 'Compute the greatest common divisor.', - 'examples': [ - 'gcd(8, 12)', - 'gcd(-4, 6)', - 'gcd(25, 15, -10)' - ], - 'seealso': [ 'lcm', 'xgcd' ] -}; - -math.docs.larger = { - 'name': 'larger', - 'category': 'Operators', - 'syntax': [ - 'x > y', - 'larger(x, y)' - ], - 'description': - 'Check if value x is larger than y. Returns 1 if x is larger than y, and 0 if not.', - 'examples': [ - '2 > 3', - '5 > 2*2', - 'a = 3.3', - 'b = 6-2.8', - '(a > b)', - '(b < a)', - '5 cm > 2 inch' - ], - 'seealso': [ - 'equal', 'unequal', 'smaller', 'smallereq', 'largereq' - ] -}; - -math.docs.largereq = { - 'name': 'largereq', - 'category': 'Operators', - 'syntax': [ - 'x >= y', - 'largereq(x, y)' - ], - 'description': - 'Check if value x is larger or equal to y. Returns 1 if x is larger or equal to y, and 0 if not.', - 'examples': [ - '2 > 1+1', - '2 >= 1+1', - 'a = 3.2', - 'b = 6-2.8', - '(a > b)' - ], - 'seealso': [ - 'equal', 'unequal', 'smallereq', 'smaller', 'largereq' - ] -}; - -math.docs.lcm = { - 'name': 'lcm', - 'category': 'Arithmetic', - 'syntax': [ - 'lcm(x, y)' - ], - 'description': 'Compute the least common multiple.', - 'examples': [ - 'lcm(4, 6)', - 'lcm(6, 21)', - 'lcm(6, 21, 5)' - ], - 'seealso': [ 'gcd' ] -}; - -math.docs.log = { - 'name': 'log', - 'category': 'Arithmetic', - 'syntax': [ - 'log(x)', - 'log(x, base)' - ], - 'description': 'Compute the logarithm of a value. If no base is provided, the natural logarithm of x is calculated. If base if provided, the logarithm is calculated for the specified base. log(x, base) is defined as log(x) / log(base).', - 'examples': [ - 'log(3.5)', - 'a = log(2.4)', - 'exp(a)', - '10 ^ 3', - 'log(1000, 10)', - 'log(1000) / log(10)', - 'b = logb(1024, 2)', - '2 ^ b' - ], - 'seealso': [ - 'exp', - 'log10' - ] -}; -math.docs.log10 = { - 'name': 'log10', - 'category': 'Arithmetic', - 'syntax': [ - 'log10(x)' - ], - 'description': 'Compute the 10-base logarithm of a value.', - 'examples': [ - 'log10(1000)', - '10 ^ 3', - 'log10(0.01)', - 'log(1000) / log(10)', - 'log(1000, 10)' - ], - 'seealso': [ - 'exp', - 'log' - ] -}; - -math.docs.mod = { - 'name': 'mod', - 'category': 'Operators', - 'syntax': [ - 'x % y', - 'x mod y', - 'mod(x, y)' - ], - 'description': - 'Calculates the modulus, the remainder of an integer division.', - 'examples': [ - '7 % 3', - '11 % 2', - '10 mod 4', - 'function isOdd(x) = x % 2', - 'isOdd(2)', - 'isOdd(3)' - ], - 'seealso': [] -}; - -math.docs.multiply = { - 'name': 'multiply', - 'category': 'Operators', - 'syntax': [ - 'x * y', - 'multiply(x, y)' - ], - 'description': 'multiply two values.', - 'examples': [ - '2.1 * 3.6', - 'ans / 3.6', - '2 * 3 + 4', - '2 * (3 + 4)', - '3 * 2.1 km' - ], - 'seealso': [ - 'divide' - ] -}; - -math.docs.pow = { - 'name': 'pow', - 'category': 'Operators', - 'syntax': [ - 'x ^ y', - 'pow(x, y)' - ], - 'description': - 'Calculates the power of x to y, x^y.', - 'examples': [ - '2^3 = 8', - '2*2*2', - '1 + e ^ (pi * i)' - ], - 'seealso': [ - 'unequal', 'smaller', 'larger', 'smallereq', 'largereq' - ] -}; - -math.docs.round = { - 'name': 'round', - 'category': 'Arithmetic', - 'syntax': [ - 'round(x)', - 'round(x, n)' - ], - 'description': - 'round a value towards the nearest integer.If x is complex, both real and imaginary part are rounded towards the nearest integer. When n is specified, the value is rounded to n decimals.', - 'examples': [ - 'round(3.2)', - 'round(3.8)', - 'round(-4.2)', - 'round(-4.8)', - 'round(pi, 3)', - 'round(123.45678, 2)' - ], - 'seealso': ['ceil', 'floor', 'fix'] -}; - -math.docs.sign = { - 'name': 'sign', - 'category': 'Arithmetic', - 'syntax': [ - 'sign(x)' - ], - 'description': - 'Compute the sign of a value. The sign of a value x is 1 when x>1, -1 when x<0, and 0 when x=0.', - 'examples': [ - 'sign(3.5)', - 'sign(-4.2)', - 'sign(0)' - ], - 'seealso': [ - 'abs' - ] -}; - -math.docs.smaller = { - 'name': 'smaller', - 'category': 'Operators', - 'syntax': [ - 'x < y', - 'smaller(x, y)' - ], - 'description': - 'Check if value x is smaller than value y. Returns 1 if x is smaller than y, and 0 if not.', - 'examples': [ - '2 < 3', - '5 < 2*2', - 'a = 3.3', - 'b = 6-2.8', - '(a < b)', - '5 cm < 2 inch' - ], - 'seealso': [ - 'equal', 'unequal', 'larger', 'smallereq', 'largereq' - ] -}; - -math.docs.smallereq = { - 'name': 'smallereq', - 'category': 'Operators', - 'syntax': [ - 'x <= y', - 'smallereq(x, y)' - ], - 'description': - 'Check if value x is smaller or equal to value y. Returns 1 if x is smaller than y, and 0 if not.', - 'examples': [ - '2 < 1+1', - '2 <= 1+1', - 'a = 3.2', - 'b = 6-2.8', - '(a < b)' - ], - 'seealso': [ - 'equal', 'unequal', 'larger', 'smaller', 'largereq' - ] -}; - -math.docs.sqrt = { - 'name': 'sqrt', - 'category': 'Arithmetic', - 'syntax': [ - 'sqrt(x)' - ], - 'description': - 'Compute the square root value. If x = y * y, then y is the square root of x.', - 'examples': [ - 'sqrt(25)', - '5 * 5', - 'sqrt(-1)' - ], - 'seealso': [ - 'square', - 'multiply' - ] -}; - -math.docs.square = { - 'name': 'square', - 'category': 'Arithmetic', - 'syntax': [ - 'square(x)' - ], - 'description': - 'Compute the square of a value. The square of x is x * x.', - 'examples': [ - 'square(3)', - 'sqrt(9)', - '3^2', - '3 * 3' - ], - 'seealso': [ - 'multiply', - 'pow', - 'sqrt', - 'cube' - ] -}; - -math.docs.subtract = { - 'name': 'subtract', - 'category': 'Operators', - 'syntax': [ - 'x - y', - 'subtract(x, y)' - ], - 'description': 'subtract two values.', - 'examples': [ - '5.3 - 2', - 'ans + 2', - '2/3 - 1/6', - '2 * 3 - 3', - '2.1 km - 500m' - ], - 'seealso': [ - 'add' - ] -}; - -math.docs.unary = { - 'name': 'unary', - 'category': 'Operators', - 'syntax': [ - '-x', - 'unary(x)' - ], - 'description': - 'Inverse the sign of a value.', - 'examples': [ - '-4.5', - '-(-5.6)' - ], - 'seealso': [ - 'add', 'subtract' - ] -}; - -math.docs.unequal = { - 'name': 'unequal', - 'category': 'Operators', - 'syntax': [ - 'x != y', - 'unequal(x, y)' - ], - 'description': - 'Check unequality of two values. Returns 1 if the values are unequal, and 0 if they are equal.', - 'examples': [ - '2+2 != 3', - '2+2 != 4', - 'a = 3.2', - 'b = 6-2.8', - 'a != b', - '50cm != 0.5m', - '5 cm != 2 inch' - ], - 'seealso': [ - 'equal', 'smaller', 'larger', 'smallereq', 'largereq' - ] -}; - -math.docs.xgcd = { - 'name': 'xgcd', - 'category': 'Arithmetic', - 'syntax': [ - 'xgcd(a, b)' - ], - 'description': 'Calculate the extended greatest common divisor for two values', - 'examples': [ - 'xgcd(8, 12)', - 'gcd(8, 12)', - 'xgcd(36163, 21199)' - ], - 'seealso': [ 'gcd', 'lcm' ] -}; - -math.docs.arg = { - 'name': 'arg', - 'category': 'Complex', - 'syntax': [ - 'arg(x)' - ], - 'description': - 'Compute the argument of a complex value. If x = a+bi, the argument is computed as atan2(b, a).', - 'examples': [ - 'arg(2 + 2i)', - 'atan2(3, 2)', - 'arg(2 - 3i)' - ], - 'seealso': [ - 're', - 'im', - 'conj', - 'abs' - ] -}; - -math.docs.conj = { - 'name': 'conj', - 'category': 'Complex', - 'syntax': [ - 'conj(x)' - ], - 'description': - 'Compute the complex conjugate of a complex value. If x = a+bi, the complex conjugate is a-bi.', - 'examples': [ - 'conj(2 + 3i)', - 'conj(2 - 3i)', - 'conj(-5.2i)' - ], - 'seealso': [ - 're', - 'im', - 'abs', - 'arg' - ] -}; - -math.docs.im = { - 'name': 'im', - 'category': 'Complex', - 'syntax': [ - 'im(x)' - ], - 'description': 'Get the imaginary part of a complex number.', - 'examples': [ - 'im(2 + 3i)', - 're(2 + 3i)', - 'im(-5.2i)', - 'im(2.4)' - ], - 'seealso': [ - 're', - 'conj', - 'abs', - 'arg' - ] -}; - -math.docs.re = { - 'name': 're', - 'category': 'Complex', - 'syntax': [ - 're(x)' - ], - 'description': 'Get the real part of a complex number.', - 'examples': [ - 're(2 + 3i)', - 'im(2 + 3i)', - 're(-5.2i)', - 're(2.4)' - ], - 'seealso': [ - 'im', - 'conj', - 'abs', - 'arg' - ] -}; - -math.docs['boolean'] = { - 'name': 'boolean', - 'category': 'Type', - 'syntax': [ - 'x', - 'boolean(x)' - ], - 'description': - 'Convert a string or number into a boolean.', - 'examples': [ - 'boolean(0)', - 'boolean(1)', - 'boolean(3)', - 'boolean("true")', - 'boolean("false")' - ], - 'seealso': [ - 'complex', 'matrix', 'range', 'string', 'unit' - ] -}; - -math.docs.complex = { - 'name': 'complex', - 'category': 'Type', - 'syntax': [ - 'complex()', - 'complex(re, im)', - 'complex(string)' - ], - 'description': - 'Create a complex number.', - 'examples': [ - 'complex()', - 'complex(2, 3)', - 'complex("7 - 2i")' - ], - 'seealso': [ - 'boolean', 'matrix', 'number', 'range', 'string', 'unit' - ] -}; - -math.docs.matrix = { - 'name': 'matrix', - 'category': 'Type', - 'syntax': [ - '[]', - '[a1, b1, ...; a2, b2, ...]', - 'matrix()', - 'matrix([...])' - ], - 'description': - 'Create a matrix.', - 'examples': [ - '[]', - '[1, 2, 3]', - '[1, 2, 3; 4, 5, 6]', - 'matrix()', - 'matrix([3, 4])' - ], - 'seealso': [ - 'boolean', 'complex', 'number', 'range', 'string', 'unit' - ] -}; - -math.docs.number = { - 'name': 'number', - 'category': 'Type', - 'syntax': [ - 'x', - 'number(x)' - ], - 'description': - 'Create a number or convert a string or boolean into a number.', - 'examples': [ - '2', - '2e3', - '4.05', - 'number(2)', - 'number("7.2")', - 'number(true)' - ], - 'seealso': [ - 'boolean', 'complex', 'matrix', 'range', 'string', 'unit' - ] -}; - -math.docs.range = { - 'name': 'range', - 'category': 'Type', - 'syntax': [ - 'start:end', - 'start:step:end', - 'range(start, end)', - 'range(start, step, end)', - 'range(string)' - ], - 'description': - 'Create a range.', - 'examples': [ - '1:5', - '3:-1:-3', - 'range(3, 6)', - 'range(0, 2, 10)', - 'range("4:10")', - 'a = [1, 2, 3; 4, 5, 6]', - 'a(:, 1:2)' - ], - 'seealso': [ - 'boolean', 'complex', 'matrix', 'number', 'string', 'unit' - ] -}; - -math.docs.string = { - 'name': 'string', - 'category': 'Type', - 'syntax': [ - '"text"', - 'string(x)' - ], - 'description': - 'Create a string or convert a value to a string', - 'examples': [ - '"Hello World!"', - 'string(4.2)', - 'string(3 + 2i)' - ], - 'seealso': [ - 'boolean', 'complex', 'matrix', 'number', 'range', 'unit' - ] -}; - -math.docs.unit = { - 'name': 'unit', - 'category': 'Type', - 'syntax': [ - 'value unit', - 'unit(value, unit)', - 'unit(string)' - ], - 'description': - 'Create a unit.', - 'examples': [ - '5.5 mm', - '3 inch', - 'unit(7.1, "kilogram")', - 'unit("23 deg")' - ], - 'seealso': [ - 'boolean', 'complex', 'matrix', 'number', 'range', 'string' - ] -}; - -math.docs.concat = { - 'name': 'concat', - 'category': 'Matrix', - 'syntax': [ - 'concat(a, b, c, ...)', - 'concat(a, b, c, ..., dim)' - ], - 'description': 'Concatenate matrices. By default, the matrices are concatenated by the first dimension. The dimension on which to concatenate can be provided as last argument.', - 'examples': [ - 'a = [1, 2; 5, 6]', - 'b = [3, 4; 7, 8]', - 'concat(a, b)', - '[a, b]', - 'concat(a, b, 2)', - '[a; b]' - ], - 'seealso': [ - 'det', 'diag', 'eye', 'inv', 'ones', 'size', 'squeeze', 'subset', 'transpose', 'zeros' - ] -}; - -math.docs.det = { - 'name': 'det', - 'category': 'Matrix', - 'syntax': [ - 'det(x)' - ], - 'description': 'Calculate the determinant of a matrix', - 'examples': [ - 'det([1, 2; 3, 4])', - 'det([-2, 2, 3; -1, 1, 3; 2, 0, -1])' - ], - 'seealso': [ - 'concat', 'diag', 'eye', 'inv', 'ones', 'size', 'squeeze', 'subset', 'transpose', 'zeros' - ] -}; - -math.docs.diag = { - 'name': 'diag', - 'category': 'Matrix', - 'syntax': [ - 'diag(x)', - 'diag(x, k)' - ], - 'description': 'Create a diagonal matrix or retrieve the diagonal of a matrix. When x is a vector, a matrix with the vector values on the diagonal will be returned. When x is a matrix, a vector with the diagonal values of the matrix is returned.When k is provided, the k-th diagonal will be filled in or retrieved, if k is positive, the values are placed on the super diagonal. When k is negative, the values are placed on the sub diagonal.', - 'examples': [ - 'diag(1:4)', - 'diag(1:4, 1)', - 'a = [1, 2, 3; 4, 5, 6; 7, 8, 9]', - 'diag(a)' - ], - 'seealso': [ - 'concat', 'det', 'eye', 'inv', 'ones', 'size', 'squeeze', 'subset', 'transpose', 'zeros' - ] -}; - -math.docs.eye = { - 'name': 'eye', - 'category': 'Matrix', - 'syntax': [ - 'eye(n)', - 'eye(m, n)', - 'eye([m, n])', - 'eye' - ], - 'description': 'Returns the identity matrix with size m-by-n. The matrix has ones on the diagonal and zeros elsewhere.', - 'examples': [ - 'eye(3)', - 'eye(3, 5)', - 'a = [1, 2, 3; 4, 5, 6]', - 'eye(size(a))' - ], - 'seealso': [ - 'concat', 'det', 'diag', 'inv', 'ones', 'size', 'squeeze', 'subset', 'transpose', 'zeros' - ] -}; - -math.docs.inv = { - 'name': 'inv', - 'category': 'Matrix', - 'syntax': [ - 'inv(x)' - ], - 'description': 'Calculate the inverse of a matrix', - 'examples': [ - 'inv([1, 2; 3, 4])', - 'inv(4)', - '1 / 4' - ], - 'seealso': [ - 'concat', 'det', 'diag', 'eye', 'ones', 'size', 'squeeze', 'subset', 'transpose', 'zeros' - ] -}; - -math.docs.ones = { - 'name': 'ones', - 'category': 'Matrix', - 'syntax': [ - 'ones(n)', - 'ones(m, n)', - 'ones(m, n, p, ...)', - 'ones([m, n])', - 'ones([m, n, p, ...])', - 'ones' - ], - 'description': 'Create a matrix containing ones.', - 'examples': [ - 'ones(3)', - 'ones(3, 5)', - 'ones([2,3]) * 4.5', - 'a = [1, 2, 3; 4, 5, 6]', - 'ones(size(a))' - ], - 'seealso': [ - 'concat', 'det', 'diag', 'eye', 'inv', 'size', 'squeeze', 'subset', 'transpose', 'zeros' - ] -}; - -math.docs.size = { - 'name': 'size', - 'category': 'Matrix', - 'syntax': [ - 'size(x)' - ], - 'description': 'Calculate the size of a matrix.', - 'examples': [ - 'size(2.3)', - 'size("hello world")', - 'a = [1, 2; 3, 4; 5, 6]', - 'size(a)', - 'size(1:6)' - ], - 'seealso': [ - 'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'squeeze', 'subset', 'transpose', 'zeros' - ] -}; - -math.docs.squeeze = { - 'name': 'squeeze', - 'category': 'Matrix', - 'syntax': [ - 'squeeze(x)' - ], - 'description': 'Remove singleton dimensions from a matrix.', - 'examples': [ - 'a = zeros(1,3,2)', - 'size(squeeze(a))', - 'b = zeros(3,1,1)', - 'size(squeeze(b))' - ], - 'seealso': [ - 'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'size', 'subset', 'transpose', 'zeros' - ] -}; - -math.docs.subset = { - 'name': 'subset', - 'category': 'Matrix', - 'syntax': [ - 'value(index)', - 'value(index) = replacement', - 'subset(value, [index])', - 'subset(value, [index], replacement)' - ], - 'description': 'Get or set a subset of a matrix or string.', - 'examples': [ - 'd = [1, 2; 3, 4]', - 'e = []', - 'e(0, 0:1) = [5, 6]', - 'e(1, :) = [7, 8]', - 'f = d * e', - 'f(1, 0)', - 'f(:, 0)' - ], - 'seealso': [ - 'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'range', 'size', 'squeeze', 'transpose', 'zeros' - ] -}; - -math.docs.transpose = { - 'name': 'transpose', - 'category': 'Matrix', - 'syntax': [ - 'x\'', - 'transpose(x)' - ], - 'description': 'Transpose a matrix', - 'examples': [ - 'a = [1, 2, 3; 4, 5, 6]', - 'a\'', - 'transpose(a)' - ], - 'seealso': [ - 'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'size', 'squeeze', 'subset', 'zeros' - ] -}; - -math.docs.zeros = { - 'name': 'zeros', - 'category': 'Matrix', - 'syntax': [ - 'zeros(n)', - 'zeros(m, n)', - 'zeros(m, n, p, ...)', - 'zeros([m, n])', - 'zeros([m, n, p, ...])', - 'zeros' - ], - 'description': 'Create a matrix containing zeros.', - 'examples': [ - 'zeros(3)', - 'zeros(3, 5)', - 'a = [1, 2, 3; 4, 5, 6]', - 'zeros(size(a))' - ], - 'seealso': [ - 'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'size', 'squeeze', 'subset', 'transpose' - ] -}; - -math.docs.factorial = { - 'name': 'factorial', - 'category': 'Probability', - 'syntax': [ - 'x!', - 'factorial(x)' - ], - 'description': 'Compute the factorial of a value', - 'examples': [ - '5!', - '5*4*3*2*1', - '3!' - ], - 'seealso': [] -}; - -math.docs.random = { - 'name': 'random', - 'category': 'Probability', - 'syntax': [ - 'random(min, max)' - ], - 'description': - 'Return a random number between 0 and 1.', - 'examples': [ - 'random()' - ], - 'seealso': [] -}; - -math.docs.randInt = { - 'name': 'randInt', - 'category': 'Probability', - 'syntax': [ - 'randInt()' - ], - 'description': - 'Return a random number between 0 and 1.', - 'examples': [ - 'randInt()' - ], - 'seealso': [] -}; -math.docs.max = { - 'name': 'max', - 'category': 'Statistics', - 'syntax': [ - 'max(a, b, c, ...)' - ], - 'description': 'Compute the maximum value of a list of values.', - 'examples': [ - 'max(2, 3, 4, 1)', - 'max(2.7, 7.1, -4.5, 2.0, 4.1)', - 'min(2.7, 7.1, -4.5, 2.0, 4.1)' - ], - 'seealso': [ - //'sum', - //'prod', - //'avg', - //'var', - //'std', - 'min' - //'median' - ] -}; - -math.docs.min = { - 'name': 'min', - 'category': 'Statistics', - 'syntax': [ - 'min(a, b, c, ...)' - ], - 'description': 'Compute the minimum value of a list of values.', - 'examples': [ - 'min(2, 3, 4, 1)', - 'min(2.7, 7.1, -4.5, 2.0, 4.1)', - 'max(2.7, 7.1, -4.5, 2.0, 4.1)' - ], - 'seealso': [ - //'sum', - //'prod', - //'avg', - //'var', - //'std', - 'max' - //'median' - ] -}; - -math.docs.acos = { - 'name': 'acos', - 'category': 'Trigonometry', - 'syntax': [ - 'acos(x)' - ], - 'description': 'Compute the inverse cosine of a value in radians.', - 'examples': [ - 'acos(0.5)', - 'acos(cos(2.3))' - ], - 'seealso': [ - 'cos', - 'acos', - 'asin' - ] -}; - -math.docs.asin = { - 'name': 'asin', - 'category': 'Trigonometry', - 'syntax': [ - 'asin(x)' - ], - 'description': 'Compute the inverse sine of a value in radians.', - 'examples': [ - 'asin(0.5)', - 'asin(sin(2.3))' - ], - 'seealso': [ - 'sin', - 'acos', - 'asin' - ] -}; - -math.docs.atan = { - 'name': 'atan', - 'category': 'Trigonometry', - 'syntax': [ - 'atan(x)' - ], - 'description': 'Compute the inverse tangent of a value in radians.', - 'examples': [ - 'atan(0.5)', - 'atan(tan(2.3))' - ], - 'seealso': [ - 'tan', - 'acos', - 'asin' - ] -}; - -math.docs.atan2 = { - 'name': 'atan2', - 'category': 'Trigonometry', - 'syntax': [ - 'atan2(y, x)' - ], - 'description': - 'Computes the principal value of the arc tangent of y/x in radians.', - 'examples': [ - 'atan2(2, 2) / pi', - 'angle = 60 deg in rad', - 'x = cos(angle)', - 'y = sin(angle)', - 'atan2(y, x)' - ], - 'seealso': [ - 'sin', - 'cos', - 'tan' - ] -}; - -math.docs.cos = { - 'name': 'cos', - 'category': 'Trigonometry', - 'syntax': [ - 'cos(x)' - ], - 'description': 'Compute the cosine of x in radians.', - 'examples': [ - 'cos(2)', - 'cos(pi / 4) ^ 2', - 'cos(180 deg)', - 'cos(60 deg)', - 'sin(0.2)^2 + cos(0.2)^2' - ], - 'seealso': [ - 'acos', - 'sin', - 'tan' - ] -}; - -math.docs.cot = { - 'name': 'cot', - 'category': 'Trigonometry', - 'syntax': [ - 'cot(x)' - ], - 'description': 'Compute the cotangent of x in radians. Defined as 1/tan(x)', - 'examples': [ - 'cot(2)', - '1 / tan(2)' - ], - 'seealso': [ - 'sec', - 'csc', - 'tan' - ] -}; - -math.docs.csc = { - 'name': 'csc', - 'category': 'Trigonometry', - 'syntax': [ - 'csc(x)' - ], - 'description': 'Compute the cosecant of x in radians. Defined as 1/sin(x)', - 'examples': [ - 'csc(2)', - '1 / sin(2)' - ], - 'seealso': [ - 'sec', - 'cot', - 'sin' - ] -}; - -math.docs.sec = { - 'name': 'sec', - 'category': 'Trigonometry', - 'syntax': [ - 'sec(x)' - ], - 'description': 'Compute the secant of x in radians. Defined as 1/cos(x)', - 'examples': [ - 'sec(2)', - '1 / cos(2)' - ], - 'seealso': [ - 'cot', - 'csc', - 'cos' - ] -}; - -math.docs.sin = { - 'name': 'sin', - 'category': 'Trigonometry', - 'syntax': [ - 'sin(x)' - ], - 'description': 'Compute the sine of x in radians.', - 'examples': [ - 'sin(2)', - 'sin(pi / 4) ^ 2', - 'sin(90 deg)', - 'sin(30 deg)', - 'sin(0.2)^2 + cos(0.2)^2' - ], - 'seealso': [ - 'asin', - 'cos', - 'tan' - ] -}; - -math.docs.tan = { - 'name': 'tan', - 'category': 'Trigonometry', - 'syntax': [ - 'tan(x)' - ], - 'description': 'Compute the tangent of x in radians.', - 'examples': [ - 'tan(0.5)', - 'sin(0.5) / cos(0.5)', - 'tan(pi / 4)', - 'tan(45 deg)' - ], - 'seealso': [ - 'atan', - 'sin', - 'cos' - ] -}; - -math.docs['in'] = { - 'name': 'in', - 'category': 'Units', - 'syntax': [ - 'x in unit', - 'in(x, unit)' - ], - 'description': 'Change the unit of a value.', - 'examples': [ - '5 inch in cm', - '3.2kg in g', - '16 bytes in bits' - ], - 'seealso': [] -}; - -math.docs.clone = { - 'name': 'clone', - 'category': 'Utils', - 'syntax': [ - 'clone(x)' - ], - 'description': 'Clone a variable. Creates a copy of primitive variables,and a deep copy of matrices', - 'examples': [ - 'clone(3.5)', - 'clone(2 - 4i)', - 'clone(45 deg)', - 'clone([1, 2; 3, 4])', - 'clone("hello world")' - ], - 'seealso': [] -}; - -math.docs['eval'] = { - 'name': 'eval', - 'category': 'Utils', - 'syntax': [ - 'eval(expression)', - 'eval([expr1, expr2, expr3, ...])' - ], - 'description': 'Evaluate an expression or an array with expressions.', - 'examples': [ - 'eval("2 + 3")', - 'eval("sqrt(" + 4 + ")")' - ], - 'seealso': [] -}; - -math.docs.format = { - 'name': 'format', - 'category': 'Utils', - 'syntax': [ - 'format(value)' - ], - 'description': 'Format a value of any type as string.', - 'examples': [ - 'format(2.3)', - 'format(3 - 4i)', - 'format([])' - ], - 'seealso': [] -}; - -math.docs.help = { - 'name': 'help', - 'category': 'Utils', - 'syntax': [ - 'help(object)', - 'help(string)' - ], - 'description': 'Display documentation on a function or data type.', - 'examples': [ - 'help(sqrt)', - 'help("complex")' - ], - 'seealso': [] -}; - -math.docs['import'] = { - 'name': 'import', - 'category': 'Utils', - 'syntax': [ - 'import(string)' - ], - 'description': 'Import functions from a file.', - 'examples': [ - 'import("numbers")', - 'import("./mylib.js")' - ], - 'seealso': [] -}; - -math.docs['typeof'] = { - 'name': 'typeof', - 'category': 'Utils', - 'syntax': [ - 'typeof(x)' - ], - 'description': 'Get the type of a variable.', - 'examples': [ - 'typeof(3.5)', - 'typeof(2 - 4i)', - 'typeof(45 deg)', - 'typeof("hello world")' - ], - 'seealso': [] -}; - -/** - * Compatibility shims for legacy JavaScript engines - */ - -// http://soledadpenades.com/2007/05/17/arrayindexof-in-internet-explorer/ -if(!Array.prototype.indexOf) { - Array.prototype.indexOf = function(obj){ - for(var i = 0; i < this.length; i++){ - if(this[i] == obj){ - return i; - } - } - return -1; - }; -} - -// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach -if (!Array.prototype.forEach) { - Array.prototype.forEach = function(fn, scope) { - for(var i = 0, len = this.length; i < len; ++i) { - fn.call(scope || this, this[i], i, this); - } - } -} - -// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray -if(!Array.isArray) { - Array.isArray = function (vArg) { - return Object.prototype.toString.call(vArg) === "[object Array]"; - }; -} - -// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/map -// Production steps of ECMA-262, Edition 5, 15.4.4.19 -// Reference: http://es5.github.com/#x15.4.4.19 -if (!Array.prototype.map) { - Array.prototype.map = function(callback, thisArg) { - - var T, A, k; - - if (this == null) { - throw new TypeError(" this is null or not defined"); - } - - // 1. Let O be the result of calling ToObject passing the |this| value as the argument. - var O = Object(this); - - // 2. Let lenValue be the result of calling the Get internal method of O with the argument "length". - // 3. Let len be ToUint32(lenValue). - var len = O.length >>> 0; - - // 4. If IsCallable(callback) is false, throw a TypeError exception. - // See: http://es5.github.com/#x9.11 - if (typeof callback !== "function") { - throw new TypeError(callback + " is not a function"); - } - - // 5. If thisArg was supplied, let T be thisArg; else let T be undefined. - if (thisArg) { - T = thisArg; - } - - // 6. Let A be a new array created as if by the expression new Array(len) where Array is - // the standard built-in constructor with that name and len is the value of len. - A = new Array(len); - - // 7. Let k be 0 - k = 0; - - // 8. Repeat, while k < len - while(k < len) { - - var kValue, mappedValue; - - // a. Let Pk be ToString(k). - // This is implicit for LHS operands of the in operator - // b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk. - // This step can be combined with c - // c. If kPresent is true, then - if (k in O) { - - // i. Let kValue be the result of calling the Get internal method of O with argument Pk. - kValue = O[ k ]; - - // ii. Let mappedValue be the result of calling the Call internal method of callback - // with T as the this value and argument list containing kValue, k, and O. - mappedValue = callback.call(T, kValue, k, O); - - // iii. Call the DefineOwnProperty internal method of A with arguments - // Pk, Property Descriptor {Value: mappedValue, : true, Enumerable: true, Configurable: true}, - // and false. - - // In browsers that support Object.defineProperty, use the following: - // Object.defineProperty(A, Pk, { value: mappedValue, writable: true, enumerable: true, configurable: true }); - - // For best browser support, use the following: - A[ k ] = mappedValue; - } - // d. Increase k by 1. - k++; - } - - // 9. return A - return A; - }; -} - -// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/every -if (!Array.prototype.every) { - Array.prototype.every = function(fun /*, thisp */) { - "use strict"; - - if (this == null) { - throw new TypeError(); - } - - var t = Object(this); - var len = t.length >>> 0; - if (typeof fun != "function") { - throw new TypeError(); - } - - var thisp = arguments[1]; - for (var i = 0; i < len; i++) { - if (i in t && !fun.call(thisp, t[i], i, t)) { - return false; - } - } - - return true; - }; -} - -// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/some -if (!Array.prototype.some) { - Array.prototype.some = function(fun /*, thisp */) { - "use strict"; - - if (this == null) { - throw new TypeError(); - } - - var t = Object(this); - var len = t.length >>> 0; - if (typeof fun != "function") { - throw new TypeError(); - } - - var thisp = arguments[1]; - for (var i = 0; i < len; i++) { - if (i in t && fun.call(thisp, t[i], i, t)) { - return true; - } - } - - return false; - }; -} - -// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind -if (!Function.prototype.bind) { - Function.prototype.bind = function (oThis) { - if (typeof this !== "function") { - // closest thing possible to the ECMAScript 5 internal IsCallable function - throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); - } - - var aArgs = Array.prototype.slice.call(arguments, 1), - fToBind = this, - fNOP = function () {}, - fBound = function () { - return fToBind.apply(this instanceof fNOP && oThis - ? this - : oThis, - aArgs.concat(Array.prototype.slice.call(arguments))); - }; - - fNOP.prototype = this.prototype; - fBound.prototype = new fNOP(); - - return fBound; - }; -} - -/** - * math.js library initialization - */ - -// initialise the Chain prototype with all functions and constants in math -for (var prop in math) { - if (math.hasOwnProperty(prop) && prop) { - createSelectorProxy(prop, math[prop]); - } -} - -/** - * CommonJS module exports - */ -if ((typeof module !== 'undefined') && (typeof module.exports !== 'undefined')) { - module.exports = math; -} -if (typeof exports !== 'undefined') { - exports = math; -} - -/** - * AMD module exports - */ -if (typeof(require) != 'undefined' && typeof(define) != 'undefined') { - define(function () { - return math; - }); -} - -/** - * Browser exports - */ -if (typeof(window) != 'undefined') { - if (window['math']) { - util.deepExtend(window['math'], math); - } - else { - window['math'] = math; - } -} - - -})(); diff --git a/dist/math.min.js b/dist/math.min.js index 4a587d54c..247154715 100644 --- a/dist/math.min.js +++ b/dist/math.min.js @@ -7,7 +7,7 @@ * mathematical functions, and a flexible expression parser. * * @version 0.11.2-SNAPSHOT - * @date 2013-08-04 + * @date 2013-08-07 * * @license * Copyright (C) 2013 Jos de Jong @@ -24,7 +24,8 @@ * License for the specific language governing permissions and limitations under * the License. */ -!function(){function e(e){return e instanceof Boolean||"boolean"==typeof e}function r(e,t){if(!(this instanceof r))throw new SyntaxError("Complex constructor must be called with the new operator");switch(arguments.length){case 0:this.re=0,this.im=0;break;case 2:if(!g(e)||!g(t))throw new TypeError("Two numbers expected in Complex constructor");this.re=e,this.im=t;break;default:if(0!=arguments.length&&2!=arguments.length)throw new SyntaxError("Two or zero arguments expected in Complex constructor")}}function t(e){e&&rr.extend(this,e)}function n(e){if(!(this instanceof n))throw new SyntaxError("Matrix constructor must be called with the new operator");if(e instanceof n||e instanceof d)this._data=e.toArray();else if(Array.isArray(e))this._data=e;else{if(null!=e)throw new TypeError("Unsupported type of data ("+er["typeof"](e)+")");this._data=[]}this._size=rr.size(this._data)}function a(e,r){return rr.validateIndex(r,e.length),e[r]}function i(e,r){return r.forEach(function(r){e=a(e,r)}),er.clone(e)}function o(e,r){var t=r[0];return t.map?t.map(function(r){return a(e,r)}):[a(e,t)]}function s(e,r){var t=r[0],n=r[1];if(t.map)return n.map?t.map(function(r){var t=a(e,r);return n.map(function(e){return a(t,e)})}):t.map(function(r){return[a(a(e,r),n)]});if(n.map){var i=a(e,t);return[n.map(function(e){return a(i,e)})]}return[[a(a(e,t),n)]]}function u(e,r,t){var n=t==r.length-1,i=r[t],o=function(i){var o=a(e,i);return n?o:u(o,r,t+1)};return i.map?i.map(o):[o(i)]}function f(e,r,t){if(rr.validateIndex(r),Array.isArray(t))throw new TypeError("Dimension mismatch, value expected instead of array");e[r]=t}function l(e,r,t,n){var a=!1;t.length>r.length&&(a=!0);for(var i=0;ir[i])&&(r[i]=o+1,a=!0)}a&&rr.resize(e,r,0);var s=r.length;t.forEach(function(r,t){s-1>t?e=e[r]:e[r]=n})}function c(e,r,t,n){var a=t[0];rr.validateIndex(a),a+1>r[0]&&(rr.resize(e,[a+1],0),r[0]=a+1),e[a]=n}function m(e,r,t,n){var a=t[0],i=t[1];rr.validateIndex(a),rr.validateIndex(i);var o=!1;a+1>(r[0]||0)&&(r[0]=a+1,o=!0),i+1>(r[1]||0)&&(r[1]=i+1,o=!0),o&&rr.resize(e,r,0),e[a][i]=n}function h(e,r,t,n,a){var i=n==t.length-1,o=t[n],s=function(o,s){if(i)f(e,o,a[s]),o+1>(r[n]||0)&&(r[n]=o+1);else{var u=e[o];Array.isArray(u)||(e[o]=u=[u]),o+1>(r[n]||0)&&(r[n]=o+1),h(u,r,t,n+1,a[s])}};if(o.map){var u=o.size&&o.size()||o.length;if(u!=a.length)throw new RangeError("Dimensions mismatch ("+u+" != "+a.length+")");o.map(s)}else s(o,0)}function p(e){for(var r=0,t=e.length;t>r;r++){var n=e[r];Array.isArray(n)?p(n):void 0==n&&(e[r]=0)}}function g(e){return e instanceof Number||"number"==typeof e}function v(e){return e==Math.round(e)}function d(e,r,t){if(!(this instanceof d))throw new SyntaxError("Range constructor must be called with the new operator");if(null!=e&&!g(e))throw new TypeError("Parameter start must be a number");if(null!=t&&!g(t))throw new TypeError("Parameter end must be a number");if(null!=r&&!g(r))throw new TypeError("Parameter step must be a number");this.start=null!=e?e:0,this.end=null!=t?t:0,this.step=null!=r?r:1}function y(e,r){var t=er.type.Selector,n=Array.prototype.slice;t.prototype[e]="function"==typeof r?function(){var e=[this.value].concat(n.call(arguments,0));return new t(r.apply(this,e))}:new t(r)}function x(e){return e instanceof String||"string"==typeof e}function w(e,r){if(!(this instanceof w))throw new Error("Unit constructor must be called with the new operator");if(null!=e&&!g(e))throw new TypeError("First parameter in Unit constructor must be a number");if(null!=r&&!x(r))throw new TypeError("Second parameter in Unit constructor must be a string");if(null!=r){var t=b(r);if(!t)throw new SyntaxError('String "'+r+'" is no unit');this.unit=t.unit,this.prefix=t.prefix}else this.unit=w.UNIT_NONE,this.prefix=w.PREFIX_NONE;null!=e?(this.value=this._normalize(e),this.fixPrefix=!1):(this.value=null,this.fixPrefix=!0)}function b(e){for(var r=w.UNITS,t=0,n=r.length;n>t;t++){var a=r[t];if(rr.endsWith(e,a.name)){var i=e.length-a.name.length,o=e.substring(0,i),s=a.prefixes[o];if(void 0!==s)return{unit:a,prefix:s}}}return null}function E(e,r){var t=void 0;if(2==arguments.length){var n=er["typeof"](r);t="Function "+e+"("+n+") not supported"}else if(arguments.length>2){for(var a=[],i=1;ia;a++)if(r[a].find(n).length>0){this.hasContextParams=!0;break}}function q(e){this.nodes=e||[]}function z(){this.params=[],this.visible=[]}function R(e,r,t){this.name=e,this.expr=r,this.scope=t}function C(e,r,t,n,a){this.name=e,this.params=r,this.paramScopes=t,this.expr=n,this.scope=a,this.hasContextParams=!1;for(var i={type:er.type.SymbolNode,properties:{name:"end"}},o=0,s=r.length;s>o;o++)if(r[o].find(i).length>0){this.hasContextParams=!0;break}}function U(e,r,t,n,a){this.name=e,this.variables=r,this.expr=t,this.scope=a,this.fn=function(){var a=r?r.length:0;if(arguments.length!=a)throw O(e,arguments.length,a);for(var i=0;a>i;i++)n.set(r[i],arguments[i]);return t.eval()},this.fn.toString=function(){return e+"("+r.join(", ")+")"}}function L(e,t){var n=t.re*t.re+t.im*t.im;return 0!=n?r.create((e.re*t.re+e.im*t.im)/n,(e.im*t.re-e.re*t.im)/n):r.create(0!=e.re?e.re/0:0,0!=e.im?e.im/0:0)}function I(e,r){if(r>0)return e>0?e%r:0==e?0:e-r*Math.floor(e/r);if(0==r)return e;throw new Error("Cannot calculate mod for a negative divisor")}function _(e,t){return 0==e.im?0==t.im?e.re*t.re:0==t.re?new r(0,e.re*t.im):new r(e.re*t.re,e.re*t.im):0==e.re?0==t.im?new r(0,e.im*t.re):0==t.re?-e.im*t.im:new r(-e.im*t.im,e.im*t.re):0==t.im?new r(e.re*t.re,e.im*t.re):0==t.re?new r(-e.im*t.im,e.re*t.im):new r(e.re*t.re-e.im*t.im,e.re*t.im+e.im*t.re)}function P(e,r){var t=er.log(e),n=er.multiply(t,r);return er.exp(n)}function B(e,r){if(r){var t=Math.pow(10,r);return Math.round(e*t)/t}return Math.round(e)}function G(e){if(Array.isArray(e)||e instanceof n||e instanceof d){for(var r=e.valueOf(),t="[",a=r.length,i=0;a>i;i++)0!=i&&(t+=", "),t+=G(r[i]);return t+="]"}return g(e)?rr.formatNumber(e):e.toString()}function j(e,r,t,n){if(t>n){if(e.length!=r.length)throw new Error("Dimensions mismatch ("+e.length+" != "+r.length+")");for(var a=[],i=0;is&&!(o>=t);s++){for(var u=s;0==e[u][o];)if(u++,u==r&&(u=s,o++,o==t))return rr.deepEqual(e,er.eye(r).valueOf())?er.round(i,6):0;if(u!=s){for(var f=0;t>f;f++){var l=e[u][f];e[u][f]=e[s][f],e[s][f]=l}i*=-1}for(var c=e[s][o],f=0;t>f;f++)e[s][f]=e[s][f]/c;i*=c;for(var m=0;r>m;m++)if(m!=s)for(var h=e[m][o],f=0;t>f;f++)e[m][f]=e[m][f]-e[s][f]*h;o++}return rr.deepEqual(e,er.eye(r).valueOf())?er.round(i,6):0}function F(e,r,t){var n,a,i,o,s,u=er.add,f=er.unary,l=er.multiply,c=er.divide;if(1==r){if(o=e[0][0],0==o)throw Error("Cannot calculate inverse, determinant is zero");return[[c(1,o)]]}if(2==r){var m=er.det(e);if(0==m)throw Error("Cannot calculate inverse, determinant is zero");return[[c(e[1][1],m),c(f(e[0][1]),m)],[c(f(e[1][0]),m),c(e[0][0],m)]]}var h=e.concat();for(n=0;r>n;n++)h[n]=h[n].concat();for(var p=er.eye(r).valueOf(),g=0;t>g;g++){for(n=g;r>n&&0==h[n][g];)n++;if(n==r||0==h[n][g])throw Error("Cannot calculate inverse, determinant is zero");n!=g&&(s=h[g],h[g]=h[n],h[n]=s,s=p[g],p[g]=p[n],p[n]=s);var v=h[g],d=p[g];for(n=0;r>n;n++){var y=h[n],x=p[n];if(n!=g){if(0!=y[g]){for(i=c(f(y[g]),v[g]),a=g;t>a;a++)y[a]=u(y[a],l(i,v[a]));for(a=0;t>a;a++)x[a]=u(x[a],l(i,d[a]))}}else{for(i=v[g],a=g;t>a;a++)y[a]=c(y[a],i);for(a=0;t>a;a++)x[a]=c(x[a],i)}}}return p}function V(e){if(1==e.length)return V(e[0]);for(var r=0,t=e.length;t>r;r++){var n=e[r];Array.isArray(n)&&(e[r]=V(n))}return e}function H(e,r){var t,a;return Array.isArray(e)||e instanceof d?(t=er.matrix(e),a=t.get(r),a.valueOf()):e instanceof n?e.get(r):x(e)?D(e,r):(t=er.matrix([e]),a=t.get(r),a.valueOf())}function D(e,r){var t,n;if(r=r.valueOf(),1!=r.length)throw new RangeError("Dimension mismatch ("+r.length+" != 1)");Array.isArray(r)&&(r=r[0]),r=r.valueOf(),Array.isArray(r)||(r=[r]);var a="",i=e.length;for(t=0,n=r.length;n>t;t++){var o=r[t];rr.validateIndex(o,i),a+=e.charAt(o)}return a}function Y(e,r,t){if(Array.isArray(e)||e instanceof d){var a=er.matrix(er.clone(e));return a.set(r,t),a.valueOf()}return e instanceof n?e.clone().set(r,t):x(e)?W(e,r,t):(a=er.matrix([e]),a.set(r,t),a.isScalar()?a.toScalar():a.valueOf())}function W(e,r,t){var n,a;if(r=r.valueOf(),1!=r.length)throw new RangeError("Dimension mismatch ("+r.length+" != 1)");if(Array.isArray(r)&&(r=r[0]),r=r.valueOf(),Array.isArray(r)||(r=[r]),r.length!=t.length)throw new RangeError("Dimension mismatch ("+r.length+" != "+t.length+")");var i=e.length,o=[];for(n=0;i>n;n++)o[n]=e.charAt(n);for(n=0,a=r.length;a>n;n++){var s=r[n];rr.validateIndex(s),o[s]=t.charAt(n)}if(o.length>i)for(n=i-1,a=o.length;a>n;n++)o[n]||(o[n]=" ");return o.join("")}function Q(e){for(var r=er.larger,t=e[0],n=1,a=e.length;a>n;n++){var i=e[n];r(i,t)&&(t=i)}return t}function K(e,r,t){for(var n=er.larger,a=[],i=0;t>i;i++){for(var o=e[0][i],s=1;r>s;s++){var u=e[s][i];n(u,o)&&(o=u)}a[i]=o}return a}function Z(e){for(var r=er.smaller,t=e[0],n=1,a=e.length;a>n;n++){var i=e[n];r(i,t)&&(t=i)}return t}function X(e,r,t){for(var n=er.smaller,a=[],i=0;t>i;i++){for(var o=e[0][i],s=1;r>s;s++){var u=e[s][i];n(u,o)&&(o=u)}a[i]=o}return a}function $(e,r,t){(t.override||void 0===er[e])&&(er[e]=t.wrap&&"function"==typeof r?function(){for(var e=[],t=0,n=arguments.length;n>t;t++)e[t]=arguments[t].valueOf();return r.apply(er,e)}:r,y(e,r))}function J(e){return"function"==typeof e||g(e)||x(e)||e instanceof r||e instanceof w}var er={type:{},expr:{node:{handlers:{}}},docs:{},options:{precision:5}},rr=function(){function e(r){if(Array.isArray(r)){var t=r.length;if(t){var n=e(r[0]);return 0==n[0]?[0].concat(n):[t].concat(n)}return[t]}return[]}function r(e,t,n){var a,i=e.length;if(i!=t[n])throw new RangeError("Dimension mismatch ("+i+" != "+t[n]+")");if(na;a++){var s=e[a];if(!Array.isArray(s))throw new RangeError("Dimension mismatch ("+(t.length-1)+" < "+t.length+")");r(e[a],t,o)}}else for(a=0;i>a;a++)if(Array.isArray(e[a]))throw new RangeError("Dimension mismatch ("+(t.length+1)+" > "+t.length+")")}function t(e,r,n){if(n 0)");t(a,r,n+1)}else if(e.length)throw new RangeError("Dimension mismatch ("+e.length+" > 0)")}function a(e,r,t,n){if(!Array.isArray(e))throw new TypeError("Array expected");var i=e.length,o=r[t];if(i!=o){if(o>e.length)for(var s=e.length;o>s;s++)e[s]=n?er.clone(n):0;else e.length=r[t];i=e.length}if(ts;s++)f=e[s],Array.isArray(f)||(f=[f],e[s]=f),a(f,r,u,n)}else for(s=0;i>s;s++){for(var f=e[s];Array.isArray(f);)f=f[0];e[s]=f}}var i={};i.formatNumber=function(e,r){if(1/0===e)return"Infinity";if(e===-1/0)return"-Infinity";if(isNaN(e))return"NaN";var t=Math.abs(e);if(t>.001&&1e5>t||0==t)return i.toPrecision(e,r);var n=Math.round(Math.log(t)/Math.LN10),a=e/Math.pow(10,n);return i.toPrecision(a,r)+"e"+n},i.toPrecision=function(e,r){return e.toPrecision(r).replace(o,function(e,r,t){return e.substring(0,e.length-(r.length?0:1)-t.length)})};var o=/\.(\d*?)(0+)$/g;return i.formatArray=function(e){if(Array.isArray(e)){for(var r="[",t=e.length,n=0;t>n;n++)0!=n&&(r+=", "),r+=i.formatArray(e[n]);return r+="]"}return er.format(e)},i.formatArray2d=function(e){var r="[",t=i.size(e);if(2!=t.length)throw new RangeError("Array must be two dimensional (size: "+i.formatArray(t)+")");for(var n=t[0],a=t[1],o=0;n>o;o++){0!=o&&(r+="; ");for(var s=e[o],u=0;a>u;u++){0!=u&&(r+=", ");var f=s[u];void 0!=f&&(r+=er.format(f))}}return r+="]"},i.argsToArray=function(e){var r;if(0==e.length)r=[];else if(1==e.length)r=e[0],r instanceof n&&(r=r.toVector()),r instanceof d&&(r=r.valueOf()),Array.isArray(r)||(r=[r]);else{r=[];for(var t=0;ts;s++)a[s]=t(e[s],r[s])}else for(a=[],o=e.length,s=0;o>s;s++)a[s]=t(e[s],r);else if(Array.isArray(r))for(a=[],o=r.length,s=0;o>s;s++)a[s]=t(e,r[s]);else a=t(e,r);return a},i.deepMap2=function f(e,r,t){var a,i,o;if(e instanceof n||r instanceof n)return new n(f(e.valueOf(),r.valueOf(),t));if(e instanceof d||r instanceof d)return f(e.valueOf(),r.valueOf(),t);if(Array.isArray(e))if(Array.isArray(r)){if(e.length!=r.length)throw new RangeError("Dimension mismatch ("+e.length+" != "+r.length+")");for(a=[],i=e.length,o=0;i>o;o++)a[o]=f(e[o],r[o],t)}else for(a=[],i=e.length,o=0;i>o;o++)a[o]=f(e[o],r,t);else if(Array.isArray(r))for(a=[],i=r.length,o=0;i>o;o++)a[o]=f(e,r[o],t);else a=t(e,r);return a},i.mapObject=function(e,r){var t={};for(var n in e)e.hasOwnProperty(n)&&(t[n]=r(e[n]));return t},i.deepEqual=function(e,r){var t,n,a;if(Array.isArray(e)){if(!Array.isArray(r))return!1;for(n=0,a=e.length;a>n;n++)if(!i.deepEqual(e[n],r[n]))return!1;return!0}if(e instanceof Object){if(Array.isArray(r)||!(r instanceof Object))return!1;for(t in e)if(e.hasOwnProperty(t)&&!i.deepEqual(e[t],r[t]))return!1;for(t in r)if(r.hasOwnProperty(t)&&!i.deepEqual(e[t],r[t]))return!1;return!0}return e.valueOf()==r.valueOf()},i.size=function(r){var t=e(r);return i.validate(r,t),t},i.validate=function(e,n){var a=0==n.length;if(a){if(Array.isArray(e))throw new RangeError("Dimension mismatch ("+e.length+" != 0)")}else{var o=-1!=n.indexOf(0);o?(n.forEach(function(e){if(0!=e)throw new RangeError("Invalid size, all dimensions must be either zero or non-zero (size: "+i.formatArray(n)+")")}),t(e,n,0)):r(e,n,0)}},i.validateIndex=function(e,r){if(!g(e)||!v(e))throw new TypeError("Index must be an integer (value: "+e+")");if(0>e)throw new RangeError("Index out of range ("+e+" < 0)");if(void 0!==r&&e>=r)throw new RangeError("Index out of range ("+e+" >= "+r+")")},i.resize=function(e,r,t){if(!Array.isArray(r))throw new TypeError("Size must be an array (size is "+er["typeof"](r)+")");r.forEach(function(e){if(!g(e)||!v(e)||0>e)throw new TypeError("Invalid size, must contain positive integers (size: "+i.formatArray(r)+")")});var n=-1!=r.indexOf(0);n&&r.forEach(function(e){if(0!=e)throw new RangeError("Invalid size, all dimensions must be either zero or non-zero (size: "+i.formatArray(r)+")")}),a(e,r,0,t)},i}();er.type.Complex=r,function(){function e(){for(;" "==l||" "==l;)a()}function t(e){return e>="0"&&"9">=e||"."==e}function n(e){return e>="0"&&"9">=e}function a(){f++,l=u.charAt(f)}function i(e){f=e,l=u.charAt(f)}function o(){var e,r="";if(e=f,"+"==l?a():"-"==l&&(r+=l,a()),!t(l))return i(e),null;if("."==l){if(r+=l,a(),!n(l))return i(e),null}else{for(;n(l);)r+=l,a();"."==l&&(r+=l,a())}for(;n(l);)r+=l,a();if("E"==l||"e"==l){if(r+=l,a(),("+"==l||"-"==l)&&(r+=l,a()),!n(l))return i(e),null;for(;n(l);)r+=l,a()}return r}function s(){var e=u.charAt(f+1);if("I"==l||"i"==l)return a(),"1";if(!("+"!=l&&"-"!=l||"I"!=e&&"i"!=e)){var r="+"==l?"1":"-1";return a(),a(),r}return null}var u,f,l;r.create=function(e,t){return 0==t?e:new r(e,t)},r.parse=function(t){if(u=t,f=-1,l="",!x(u))return null;a(),e();var n=o();if(n){if("I"==l||"i"==l)return a(),e(),l?null:new r(0,Number(n));e();var i=l;if("+"!=i&&"-"!=i)return e(),l?null:new r(Number(n),0);a(),e();var c=o();if(c){if("I"!=l&&"i"!=l)return null;a()}else if(c=s(),!c)return null;return"-"==i&&(c="-"==c[0]?"+"+c.substring(1):"-"+c),a(),e(),l?null:new r(Number(n),Number(c))}return(n=s())?(e(),l?null:new r(0,Number(n))):null}}(),r.prototype.clone=function(){return new r(this.re,this.im)},r.prototype.toString=function(){var e="",r=rr.formatNumber(this.re,er.options.precision),t=rr.formatNumber(this.im,er.options.precision);return e=0==this.im?r:0==this.re?1==this.im?"i":-1==this.im?"-i":t+"i":this.im>0?1==this.im?r+" + i":r+" + "+t+"i":-1==this.im?r+" - i":r+" - "+rr.formatNumber(Math.abs(this.im),er.options.precision)+"i"},er.type.Help=t,t.prototype.toString=function(){var e="\n";if(this.name&&(e+="Name: "+this.name+"\n\n"),this.category&&(e+="Category: "+this.category+"\n\n"),this.syntax&&(e+="Syntax:\n "+this.syntax.join("\n ")+"\n\n"),this.examples){var r=er.parser();e+="Examples:\n";for(var n=0;n=e})},n.prototype.toVector=function(){var e=0,r=void 0,t=[];if(this._size.forEach(function(n,a){n>1&&(e++,r=a),t[a]=0}),0==e){var n=this.toScalar();return n?[n]:[]}if(1==e){var a=[],i=function(e){Array.isArray(e)?e.forEach(i):a.push(e)};return i(this._data),a}return null},n.prototype.isVector=function(){var e=0;return this._size.forEach(function(r){r>1&&e++}),1>=e},n.prototype.toArray=function(){return er.clone(this._data)},n.prototype.valueOf=function(){return this._data},n.prototype.toString=function(){return er.format(this._data)},er.type.Range=d,d.parse=function(e){if(!x(e))return null;var r=e.split(":"),t=r.map(function(e){return Number(e)}),n=t.some(function(e){return isNaN(e)});if(n)return null;switch(t.length){case 2:return new d(t[0],1,t[1]);case 3:return new d(t[0],t[1],t[2]);default:return null}},d.prototype.clone=function(){return new d(this.start,this.step,this.end)},d.prototype.size=function(){var e=0,r=Number(this.start),t=Number(this.step),n=Number(this.end),a=n-r;return er.sign(t)==er.sign(a)?e=Math.floor(a/t)+1:0==a&&(e=1),isNaN(e)&&(e=0),[e]},d.prototype.forEach=function(e){var r=Number(this.start),t=Number(this.step),n=Number(this.end),a=0;if(t>0)for(;n>=r;)e(r,a,this),r+=t,a++;else if(0>t)for(;r>=n;)e(r,a,this),r+=t,a++},d.prototype.map=function(e){var r=[];return this.forEach(function(t,n,a){r[n]=e(t,n,a)}),r},d.prototype.toMatrix=function(){return new n(this.toArray())},d.prototype.toArray=function(){var e=[];return this.forEach(function(r,t){e[t]=r}),e},d.prototype.toVector=d.prototype.toArray,d.prototype.isVector=function(){return!0},d.prototype.toScalar=function(){var e=this.toArray();return 1==e.length?e[0]:null},d.prototype.isScalar=function(){return 1==this.size()[0]},d.prototype.valueOf=function(){return this.toArray()},d.prototype.toString=function(){var e=er.format(Number(this.start));return 1!=this.step&&(e+=":"+er.format(Number(this.step))),e+=":"+er.format(Number(this.end))},er.type.Selector=function(e){if(!(this instanceof er.type.Selector))throw new SyntaxError("Selector constructor must be called with the new operator");this.value=e instanceof er.type.Selector?e.value:e},er.type.Selector.prototype={done:function(){return this.value},get:function(e){var r=this.value;if(!r)throw Error("Selector value is undefined");return new er.type.Selector(er.subset(r,e))},set:function(e,r){var t=this.value;if(!t)throw Error("Selector value is undefined");return new er.type.Selector(er.subset(t,e,r))},valueOf:function(){return this.value},toString:function(){return er.format(this.value)}},er.type.Unit=w,function(){function e(){for(;" "==f||" "==f;)n()}function r(e){return e>="0"&&"9">=e||"."==e}function t(e){return e>="0"&&"9">=e}function n(){u++,f=s.charAt(u)}function a(e){u=e,f=s.charAt(u)}function i(){var e,i="";if(e=u,"+"==f?n():"-"==f&&(i+=f,n()),!r(f))return a(e),null;if("."==f){if(i+=f,n(),!t(f))return a(e),null}else{for(;t(f);)i+=f,n();"."==f&&(i+=f,n())}for(;t(f);)i+=f,n();if("E"==f||"e"==f){if(i+=f,n(),("+"==f||"-"==f)&&(i+=f,n()),!t(f))return a(e),null;for(;t(f);)i+=f,n()}return i}function o(){var r="";for(e();f&&" "!=f&&" "!=f;)r+=f,n();return r||null}var s,u,f;w.parse=function(r){if(s=r,u=-1,f="",!x(s))return null;n(),e();var t,a=i();return a?(t=o(),n(),e(),f?null:a&&t?new w(Number(a),t):null):(t=o(),n(),e(),f?null:new w(null,t))}}(),w.prototype.clone=function(){var e=new w;for(var r in this)this.hasOwnProperty(r)&&(e[r]=this[r]);return e},w.prototype._normalize=function(e){return(e+this.unit.offset)*this.unit.value*this.prefix.value},w.prototype._unnormalize=function(e,r){return void 0==r?e/this.unit.value/this.prefix.value-this.unit.offset:e/this.unit.value/r-this.unit.offset},w.isPlainUnit=function(e){return null!=b(e)},w.prototype.hasBase=function(e){return void 0===this.unit.base?void 0===e:this.unit.base===e},w.prototype.equalBase=function(e){return this.unit.base===e.unit.base},w.prototype.equals=function(e){return this.equalBase(e)&&this.value==e.value},w.prototype["in"]=function(e){var r;if(x(e)){if(r=new w(null,e),!this.equalBase(r))throw new Error("Units do not match");return r.value=this.value,r}if(e instanceof w){if(!this.equalBase(e))throw new Error("Units do not match");if(null!=e.value)throw new Error("Cannot convert to a unit with a value");if(null==e.unit)throw new Error("Unit expected on the right hand side of function in");return r=e.clone(),r.value=this.value,r.fixPrefix=!0,r}throw new Error("String or Unit expected as parameter")},w.prototype.toNumber=function(e){var r=this["in"](e),t=this.fixPrefix?r._bestPrefix():r.prefix;return r._unnormalize(r.value,t.value)},w.prototype.toString=function(){var e,r;if(this.fixPrefix)e=this._unnormalize(this.value),r=null!=this.value?rr.formatNumber(e,er.options.precision)+" ":"",r+=this.prefix.name+this.unit.name;else{var t=this._bestPrefix();e=this._unnormalize(this.value,t.value),r=null!=this.value?rr.formatNumber(e,er.options.precision)+" ":"",r+=t.name+this.unit.name}return r},w.prototype._bestPrefix=function(){var e=Math.abs(this.value/this.unit.value),r=w.PREFIX_NONE,t=Math.abs(Math.log(e/r.value)/Math.LN10-1.2),n=this.unit.prefixes;for(var a in n)if(n.hasOwnProperty(a)){var i=n[a];if(i.scientific){var o=Math.abs(Math.log(e/i.value)/Math.LN10-1.2);t>o&&(r=i,t=o)}}return r},w.PREFIXES={NONE:{"":{name:"",value:1,scientific:!0}},SHORT:{"":{name:"",value:1,scientific:!0},da:{name:"da",value:10,scientific:!1},h:{name:"h",value:100,scientific:!1},k:{name:"k",value:1e3,scientific:!0},M:{name:"M",value:1e6,scientific:!0},G:{name:"G",value:1e9,scientific:!0},T:{name:"T",value:1e12,scientific:!0},P:{name:"P",value:1e15,scientific:!0},E:{name:"E",value:1e18,scientific:!0},Z:{name:"Z",value:1e21,scientific:!0},Y:{name:"Y",value:1e24,scientific:!0},d:{name:"d",value:.1,scientific:!1},c:{name:"c",value:.01,scientific:!1},m:{name:"m",value:.001,scientific:!0},u:{name:"u",value:1e-6,scientific:!0},n:{name:"n",value:1e-9,scientific:!0},p:{name:"p",value:1e-12,scientific:!0},f:{name:"f",value:1e-15,scientific:!0},a:{name:"a",value:1e-18,scientific:!0},z:{name:"z",value:1e-21,scientific:!0},y:{name:"y",value:1e-24,scientific:!0}},LONG:{"":{name:"",value:1,scientific:!0},deca:{name:"deca",value:10,scientific:!1},hecto:{name:"hecto",value:100,scientific:!1},kilo:{name:"kilo",value:1e3,scientific:!0},mega:{name:"mega",value:1e6,scientific:!0},giga:{name:"giga",value:1e9,scientific:!0},tera:{name:"tera",value:1e12,scientific:!0},peta:{name:"peta",value:1e15,scientific:!0},exa:{name:"exa",value:1e18,scientific:!0},zetta:{name:"zetta",value:1e21,scientific:!0},yotta:{name:"yotta",value:1e24,scientific:!0},deci:{name:"deci",value:.1,scientific:!1},centi:{name:"centi",value:.01,scientific:!1},milli:{name:"milli",value:.001,scientific:!0},micro:{name:"micro",value:1e-6,scientific:!0},nano:{name:"nano",value:1e-9,scientific:!0},pico:{name:"pico",value:1e-12,scientific:!0},femto:{name:"femto",value:1e-15,scientific:!0},atto:{name:"atto",value:1e-18,scientific:!0},zepto:{name:"zepto",value:1e-21,scientific:!0},yocto:{name:"yocto",value:1e-24,scientific:!0}},BINARY_SHORT:{"":{name:"",value:1,scientific:!0},k:{name:"k",value:1024,scientific:!0},M:{name:"M",value:Math.pow(1024,2),scientific:!0},G:{name:"G",value:Math.pow(1024,3),scientific:!0},T:{name:"T",value:Math.pow(1024,4),scientific:!0},P:{name:"P",value:Math.pow(1024,5),scientific:!0},E:{name:"E",value:Math.pow(1024,6),scientific:!0},Z:{name:"Z",value:Math.pow(1024,7),scientific:!0},Y:{name:"Y",value:Math.pow(1024,8),scientific:!0},Ki:{name:"Ki",value:1024,scientific:!0},Mi:{name:"Mi",value:Math.pow(1024,2),scientific:!0},Gi:{name:"Gi",value:Math.pow(1024,3),scientific:!0},Ti:{name:"Ti",value:Math.pow(1024,4),scientific:!0},Pi:{name:"Pi",value:Math.pow(1024,5),scientific:!0},Ei:{name:"Ei",value:Math.pow(1024,6),scientific:!0},Zi:{name:"Zi",value:Math.pow(1024,7),scientific:!0},Yi:{name:"Yi",value:Math.pow(1024,8),scientific:!0}},BINARY_LONG:{"":{name:"",value:1,scientific:!0},kilo:{name:"kilo",value:1024,scientific:!0},mega:{name:"mega",value:Math.pow(1024,2),scientific:!0},giga:{name:"giga",value:Math.pow(1024,3),scientific:!0},tera:{name:"tera",value:Math.pow(1024,4),scientific:!0},peta:{name:"peta",value:Math.pow(1024,5),scientific:!0},exa:{name:"exa",value:Math.pow(1024,6),scientific:!0},zetta:{name:"zetta",value:Math.pow(1024,7),scientific:!0},yotta:{name:"yotta",value:Math.pow(1024,8),scientific:!0},kibi:{name:"kibi",value:1024,scientific:!0},mebi:{name:"mebi",value:Math.pow(1024,2),scientific:!0},gibi:{name:"gibi",value:Math.pow(1024,3),scientific:!0},tebi:{name:"tebi",value:Math.pow(1024,4),scientific:!0},pebi:{name:"pebi",value:Math.pow(1024,5),scientific:!0},exi:{name:"exi",value:Math.pow(1024,6),scientific:!0},zebi:{name:"zebi",value:Math.pow(1024,7),scientific:!0},yobi:{name:"yobi",value:Math.pow(1024,8),scientific:!0}}},w.PREFIX_NONE={name:"",value:1,scientific:!0},w.BASE_UNITS={NONE:{},LENGTH:{},MASS:{},TIME:{},CURRENT:{},TEMPERATURE:{},LUMINOUS_INTENSITY:{},AMOUNT_OF_SUBSTANCE:{},FORCE:{},SURFACE:{},VOLUME:{},ANGLE:{},BIT:{}};var tr=w.BASE_UNITS,nr=w.PREFIXES;w.BASE_UNIT_NONE={},w.UNIT_NONE={name:"",base:w.BASE_UNIT_NONE,value:1,offset:0},w.UNITS=[{name:"meter",base:tr.LENGTH,prefixes:nr.LONG,value:1,offset:0},{name:"inch",base:tr.LENGTH,prefixes:nr.NONE,value:.0254,offset:0},{name:"foot",base:tr.LENGTH,prefixes:nr.NONE,value:.3048,offset:0},{name:"yard",base:tr.LENGTH,prefixes:nr.NONE,value:.9144,offset:0},{name:"mile",base:tr.LENGTH,prefixes:nr.NONE,value:1609.344,offset:0},{name:"link",base:tr.LENGTH,prefixes:nr.NONE,value:.201168,offset:0},{name:"rod",base:tr.LENGTH,prefixes:nr.NONE,value:5.02921,offset:0},{name:"chain",base:tr.LENGTH,prefixes:nr.NONE,value:20.1168,offset:0},{name:"angstrom",base:tr.LENGTH,prefixes:nr.NONE,value:1e-10,offset:0},{name:"m",base:tr.LENGTH,prefixes:nr.SHORT,value:1,offset:0},{name:"ft",base:tr.LENGTH,prefixes:nr.NONE,value:.3048,offset:0},{name:"yd",base:tr.LENGTH,prefixes:nr.NONE,value:.9144,offset:0},{name:"mi",base:tr.LENGTH,prefixes:nr.NONE,value:1609.344,offset:0},{name:"li",base:tr.LENGTH,prefixes:nr.NONE,value:.201168,offset:0},{name:"rd",base:tr.LENGTH,prefixes:nr.NONE,value:5.02921,offset:0},{name:"ch",base:tr.LENGTH,prefixes:nr.NONE,value:20.1168,offset:0},{name:"mil",base:tr.LENGTH,prefixes:nr.NONE,value:254e-7,offset:0},{name:"m2",base:tr.SURFACE,prefixes:nr.SHORT,value:1,offset:0},{name:"sqin",base:tr.SURFACE,prefixes:nr.NONE,value:64516e-8,offset:0},{name:"sqft",base:tr.SURFACE,prefixes:nr.NONE,value:.09290304,offset:0},{name:"sqyd",base:tr.SURFACE,prefixes:nr.NONE,value:.83612736,offset:0},{name:"sqmi",base:tr.SURFACE,prefixes:nr.NONE,value:2589988.110336,offset:0},{name:"sqrd",base:tr.SURFACE,prefixes:nr.NONE,value:25.29295,offset:0},{name:"sqch",base:tr.SURFACE,prefixes:nr.NONE,value:404.6873,offset:0},{name:"sqmil",base:tr.SURFACE,prefixes:nr.NONE,value:6.4516e-10,offset:0},{name:"m3",base:tr.VOLUME,prefixes:nr.SHORT,value:1,offset:0},{name:"L",base:tr.VOLUME,prefixes:nr.SHORT,value:.001,offset:0},{name:"litre",base:tr.VOLUME,prefixes:nr.LONG,value:.001,offset:0},{name:"cuin",base:tr.VOLUME,prefixes:nr.NONE,value:16387064e-12,offset:0},{name:"cuft",base:tr.VOLUME,prefixes:nr.NONE,value:.028316846592,offset:0},{name:"cuyd",base:tr.VOLUME,prefixes:nr.NONE,value:.764554857984,offset:0},{name:"teaspoon",base:tr.VOLUME,prefixes:nr.NONE,value:5e-6,offset:0},{name:"tablespoon",base:tr.VOLUME,prefixes:nr.NONE,value:15e-6,offset:0},{name:"minim",base:tr.VOLUME,prefixes:nr.NONE,value:6.161152e-8,offset:0},{name:"fluiddram",base:tr.VOLUME,prefixes:nr.NONE,value:36966911e-13,offset:0},{name:"fluidounce",base:tr.VOLUME,prefixes:nr.NONE,value:2957353e-11,offset:0},{name:"gill",base:tr.VOLUME,prefixes:nr.NONE,value:.0001182941,offset:0},{name:"cup",base:tr.VOLUME,prefixes:nr.NONE,value:.0002365882,offset:0},{name:"pint",base:tr.VOLUME,prefixes:nr.NONE,value:.0004731765,offset:0},{name:"quart",base:tr.VOLUME,prefixes:nr.NONE,value:.0009463529,offset:0},{name:"gallon",base:tr.VOLUME,prefixes:nr.NONE,value:.003785412,offset:0},{name:"beerbarrel",base:tr.VOLUME,prefixes:nr.NONE,value:.1173478,offset:0},{name:"oilbarrel",base:tr.VOLUME,prefixes:nr.NONE,value:.1589873,offset:0},{name:"hogshead",base:tr.VOLUME,prefixes:nr.NONE,value:.238481,offset:0},{name:"fldr",base:tr.VOLUME,prefixes:nr.NONE,value:36966911e-13,offset:0},{name:"floz",base:tr.VOLUME,prefixes:nr.NONE,value:2957353e-11,offset:0},{name:"gi",base:tr.VOLUME,prefixes:nr.NONE,value:.0001182941,offset:0},{name:"cp",base:tr.VOLUME,prefixes:nr.NONE,value:.0002365882,offset:0},{name:"pt",base:tr.VOLUME,prefixes:nr.NONE,value:.0004731765,offset:0},{name:"qt",base:tr.VOLUME,prefixes:nr.NONE,value:.0009463529,offset:0},{name:"gal",base:tr.VOLUME,prefixes:nr.NONE,value:.003785412,offset:0},{name:"bbl",base:tr.VOLUME,prefixes:nr.NONE,value:.1173478,offset:0},{name:"obl",base:tr.VOLUME,prefixes:nr.NONE,value:.1589873,offset:0},{name:"g",base:tr.MASS,prefixes:nr.SHORT,value:.001,offset:0},{name:"gram",base:tr.MASS,prefixes:nr.LONG,value:.001,offset:0},{name:"ton",base:tr.MASS,prefixes:nr.SHORT,value:907.18474,offset:0},{name:"tonne",base:tr.MASS,prefixes:nr.SHORT,value:1e3,offset:0},{name:"grain",base:tr.MASS,prefixes:nr.NONE,value:6479891e-11,offset:0},{name:"dram",base:tr.MASS,prefixes:nr.NONE,value:.0017718451953125,offset:0},{name:"ounce",base:tr.MASS,prefixes:nr.NONE,value:.028349523125,offset:0},{name:"poundmass",base:tr.MASS,prefixes:nr.NONE,value:.45359237,offset:0},{name:"hundredweight",base:tr.MASS,prefixes:nr.NONE,value:45.359237,offset:0},{name:"stick",base:tr.MASS,prefixes:nr.NONE,value:.115,offset:0},{name:"gr",base:tr.MASS,prefixes:nr.NONE,value:6479891e-11,offset:0},{name:"dr",base:tr.MASS,prefixes:nr.NONE,value:.0017718451953125,offset:0},{name:"oz",base:tr.MASS,prefixes:nr.NONE,value:.028349523125,offset:0},{name:"lbm",base:tr.MASS,prefixes:nr.NONE,value:.45359237,offset:0},{name:"cwt",base:tr.MASS,prefixes:nr.NONE,value:45.359237,offset:0},{name:"s",base:tr.TIME,prefixes:nr.SHORT,value:1,offset:0},{name:"min",base:tr.TIME,prefixes:nr.NONE,value:60,offset:0},{name:"h",base:tr.TIME,prefixes:nr.NONE,value:3600,offset:0},{name:"seconds",base:tr.TIME,prefixes:nr.LONG,value:1,offset:0},{name:"second",base:tr.TIME,prefixes:nr.LONG,value:1,offset:0},{name:"sec",base:tr.TIME,prefixes:nr.LONG,value:1,offset:0},{name:"minutes",base:tr.TIME,prefixes:nr.NONE,value:60,offset:0},{name:"minute",base:tr.TIME,prefixes:nr.NONE,value:60,offset:0},{name:"hours",base:tr.TIME,prefixes:nr.NONE,value:3600,offset:0},{name:"hour",base:tr.TIME,prefixes:nr.NONE,value:3600,offset:0},{name:"day",base:tr.TIME,prefixes:nr.NONE,value:86400,offset:0},{name:"days",base:tr.TIME,prefixes:nr.NONE,value:86400,offset:0},{name:"rad",base:tr.ANGLE,prefixes:nr.NONE,value:1,offset:0},{name:"deg",base:tr.ANGLE,prefixes:nr.NONE,value:.017453292519943295,offset:0},{name:"grad",base:tr.ANGLE,prefixes:nr.NONE,value:.015707963267948967,offset:0},{name:"cycle",base:tr.ANGLE,prefixes:nr.NONE,value:6.283185307179586,offset:0},{name:"A",base:tr.CURRENT,prefixes:nr.SHORT,value:1,offset:0},{name:"ampere",base:tr.CURRENT,prefixes:nr.LONG,value:1,offset:0},{name:"K",base:tr.TEMPERATURE,prefixes:nr.NONE,value:1,offset:0},{name:"degC",base:tr.TEMPERATURE,prefixes:nr.NONE,value:1,offset:273.15},{name:"degF",base:tr.TEMPERATURE,prefixes:nr.NONE,value:1/1.8,offset:459.67},{name:"degR",base:tr.TEMPERATURE,prefixes:nr.NONE,value:1/1.8,offset:0},{name:"kelvin",base:tr.TEMPERATURE,prefixes:nr.NONE,value:1,offset:0},{name:"celsius",base:tr.TEMPERATURE,prefixes:nr.NONE,value:1,offset:273.15},{name:"fahrenheit",base:tr.TEMPERATURE,prefixes:nr.NONE,value:1/1.8,offset:459.67},{name:"rankine",base:tr.TEMPERATURE,prefixes:nr.NONE,value:1/1.8,offset:0},{name:"mol",base:tr.AMOUNT_OF_SUBSTANCE,prefixes:nr.NONE,value:1,offset:0},{name:"mole",base:tr.AMOUNT_OF_SUBSTANCE,prefixes:nr.NONE,value:1,offset:0},{name:"cd",base:tr.LUMINOUS_INTENSITY,prefixes:nr.NONE,value:1,offset:0},{name:"candela",base:tr.LUMINOUS_INTENSITY,prefixes:nr.NONE,value:1,offset:0},{name:"N",base:tr.FORCE,prefixes:nr.SHORT,value:1,offset:0},{name:"newton",base:tr.FORCE,prefixes:nr.LONG,value:1,offset:0},{name:"lbf",base:tr.FORCE,prefixes:nr.NONE,value:4.4482216152605,offset:0},{name:"poundforce",base:tr.FORCE,prefixes:nr.NONE,value:4.4482216152605,offset:0},{name:"b",base:tr.BIT,prefixes:nr.BINARY_SHORT,value:1,offset:0},{name:"bits",base:tr.BIT,prefixes:nr.BINARY_LONG,value:1,offset:0},{name:"B",base:tr.BIT,prefixes:nr.BINARY_SHORT,value:8,offset:0},{name:"bytes",base:tr.BIT,prefixes:nr.BINARY_LONG,value:8,offset:0}],er.pi=Math.PI,er.e=Math.E,er.tau=2*Math.PI,er.i=new r(0,1),er.Infinity=1/0,er.NaN=0/0,er["true"]=!0,er["false"]=!1,er.E=Math.E,er.LN2=Math.LN2,er.LN10=Math.LN10,er.LOG2E=Math.LOG2E,er.LOG10E=Math.LOG10E,er.PI=Math.PI,er.SQRT1_2=Math.SQRT1_2,er.SQRT2=Math.SQRT2,er.expr.node.Node=A,A.prototype.eval=function(){throw new Error("Cannot evaluate a Node interface") -},A.prototype.find=function(e){return this.match(e)?[this]:[]},A.prototype.match=function(e){var r=!0;if(e&&(!e.type||this instanceof e.type||(r=!1),r&&e.properties))for(var t in e.properties)if(e.properties.hasOwnProperty(t)&&this[t]!=e.properties[t]){r=!1;break}return r},A.prototype.toString=function(){return""},N.prototype=new A,er.expr.node.ConstantNode=N,N.prototype.eval=function(){return this.value},N.prototype.toString=function(){return er.format(this.value)},M.prototype=new A,er.expr.node.OperatorNode=M,M.prototype.eval=function(){return this.fn.apply(this,this.params.map(function(e){return e.eval()}))},M.prototype.find=function(e){var r=[];this.match(e)&&r.push(this);var t=this.params;if(t)for(var n=0,a=t.length;a>n;n++)r=r.concat(t[n].find(e));return r},M.prototype.toString=function(){var e=this.params;if(this.fn===er.unary)return"-"+e[0].toString();switch(e.length){case 1:return e[0].toString()+this.name;case 2:var r=e[0].toString();e[0]instanceof M&&(r="("+r+")");var t=e[1].toString();return e[1]instanceof M&&(t="("+t+")"),r+" "+this.name+" "+t;default:return this.name+"("+this.params.join(", ")+")"}},S.prototype=new A,er.expr.node.SymbolNode=S,S.prototype.eval=function(){var e=this.scope.get(this.name);if(void 0===e)throw new Error("Undefined symbol "+this.name);return e},S.prototype.toString=function(){return this.name},T.prototype=new A,er.expr.node.ParamsNode=T,T.prototype.eval=function(){var e,r,t=this.object;if(void 0==t)throw new Error("Node undefined");var n=t.eval();if(this.hasContextParams){var a,i=this.paramScopes;if(a=n.size?n.size():void 0!==n.length?[n.length]:[],i&&a)for(e=0,r=this.params.length;r>e;e++){var o=i[e];o&&o.set("end",a[e]-1)}}var s=this.params,u=[];for(e=0,r=this.params.length;r>e;e++)u[e]=s[e].eval();return"function"==typeof n?n.apply(this,u):er.subset(n,u)},T.prototype.find=function(e){var r=[];this.match(e)&&r.push(this),this.object&&(r=r.concat(this.object.find(e)));var t=this.params;if(t)for(var n=0,a=t.length;a>n;n++)r=r.concat(t[n].find(e));return r},T.prototype.toString=function(){var e=this.object?this.object.toString():"";return this.params&&(e+="("+this.params.join(", ")+")"),e},q.prototype=new A,er.expr.node.MatrixNode=q,function(){function e(e){for(var r=[],t=e.length,a=0;t>a;a++){for(var i=e[a],o=i.length,s=null,u=null,f=0;o>f;f++){var l,c=er.clone(i[f]);if(c instanceof n){if(l=c.size(),c=c.valueOf(),1==l.length)c=[c],l=[1,l[0]];else if(l.length>2)throw new Error("Cannot merge a multi dimensional matrix")}else c instanceof d?(c=[c.valueOf()],l=[1,c[0].length]):Array.isArray(c)?(l=[1,c.length],c=[c]):(l=[1,1],c=[[c]]);if(null==s)s=c,u=l[0];else{if(l[0]!=u)throw new Error("Dimension mismatch ("+l[0]+" != "+u+")");for(var m=0;u>m;m++)s[m]=s[m].concat(c[m])}}r=r.concat(s)}return r}q.prototype.eval=function(){for(var r=this.nodes,t=[],a=!1,i=0,o=r.length;o>i;i++){for(var s=r[i],u=[],f=0,l=s.length;l>f;f++){var c=s[f].eval();(c instanceof n||c instanceof d||Array.isArray(c))&&(a=!0),u[f]=c}t[i]=u}return a&&(t=e(t)),new n(t)},q.prototype.find=function(e){var r=[];this.match(e)&&r.push(this);for(var t=this.nodes,n=0,a=t.length;a>n;n++)for(var i=t[n],o=0,s=i.length;s>o;o++)r=r.concat(i[o].find(e));return r},q.prototype.toString=function(){return rr.formatArray(this.nodes)}}(),z.prototype=new A,er.expr.node.BlockNode=z,z.prototype.add=function(e,r){var t=this.params.length;this.params[t]=e,this.visible[t]=void 0!=r?r:!0},z.prototype.eval=function(){for(var e=[],r=0,t=this.params.length;t>r;r++){var n=this.params[r].eval();this.visible[r]&&e.push(n)}return e},z.prototype.find=function(e){var r=[];this.match(e)&&r.push(this);var t=this.params;if(t)for(var n=0,a=t.length;a>n;n++)r=r.concat(t[n].find(e));return r},z.prototype.toString=function(){for(var e=[],r=0,t=this.params.length;t>r;r++)this.visible[r]&&e.push("\n "+this.params[r].toString());return"["+e.join(",")+"\n]"},R.prototype=new A,er.expr.node.AssignmentNode=R,R.prototype.eval=function(){if(void 0===this.expr)throw new Error("Undefined symbol "+this.name);var e=this.expr.eval();return this.scope.set(this.name,e),e},R.prototype.find=function(e){var r=[];return this.match(e)&&r.push(this),this.expr&&(r=r.concat(this.expr.find(e))),r},R.prototype.toString=function(){return this.name+" = "+this.expr.toString()},C.prototype=new A,er.expr.node.UpdateNode=C,C.prototype.eval=function(){if(void 0===this.expr)throw new Error("Undefined symbol "+this.name);var e;this.params;var r=this.scope.get(this.name);if(void 0==r)throw new Error("Undefined symbol "+this.name);if(this.hasContextParams){var t,n=this.paramScopes;if(t=r.size?r.size():void 0!==r.length?[r.length]:[],n&&t)for(var a=0,i=this.params.length;i>a;a++){var o=n[a];o&&o.set("end",t[a]-1)}}var s=[];this.params.forEach(function(e){s.push(e.eval())});var u=this.expr.eval();return e=er.subset(r,s,u),this.scope.set(this.name,e),e},C.prototype.find=function(e){var r=[];this.match(e)&&r.push(this);var t=this.params;if(t)for(var n=0,a=t.length;a>n;n++)r=r.concat(t[n].find(e));return this.expr&&(r=r.concat(this.expr.find(e))),r},C.prototype.toString=function(){var e="";return e+=this.name,this.params&&this.params.length&&(e+="("+this.params.join(", ")+")"),e+=" = ",e+=this.expr.toString()},U.prototype=new A,er.expr.node.FunctionNode=U,U.prototype.eval=function(){return this.scope.set(this.name,this.fn),this.fn},U.prototype.find=function(e){var r=[];return this.match(e)&&r.push(this),this.expr&&(r=r.concat(this.expr.find(e))),r},U.prototype.toString=function(){return this.fn.toString()},er.expr.Scope=function(){if(this.parentScope=null,this.subScopes=null,this.symbols={},this.cache={},arguments.length>0){var e=arguments[0];e instanceof er.expr.Scope?this.parentScope=e:e instanceof Object&&(this.symbols=e)}if(arguments.length>1){var r=arguments[1];r instanceof Object&&(this.symbols=r)}},er.expr.Scope.prototype={createSubScope:function(){var e=new er.expr.Scope(this);return this.subScopes||(this.subScopes=[]),this.subScopes.push(e),e},get:function(e){var r;if(r=this.symbols[e],void 0!==r)return r;var t=this.cache[e];if(t)return t[e];for(var n=this.parentScope;n;){if(r=n.symbols[e],void 0!==r)return this.cache[e]=n.symbols,r;n=n.parentScope}return r=er[e],void 0!==r?(this.cache[e]=er,r):w.isPlainUnit(e)?(r=new w(null,e),this.cache[e]={},this.cache[e][e]=r,r):void 0},has:function(e){return void 0!==this.symbols[e]},set:function(e,r){return this.symbols[e]=r},remove:function(e){delete this.symbols[e]},clear:function(){var e=this.symbols;for(var r in e)e.hasOwnProperty(r)&&delete e[r];if(this.subScopes)for(var t=this.subScopes,n=0,a=t.length;a>n;n++)t[n].clear();this.clearCache()},clearCache:function(){this.cache={}}},er.expr.Parser=function(){if(!(this instanceof er.expr.Parser))throw new SyntaxError("Parser constructor must be called with the new operator");this.scope=new er.expr.Scope},er.expr.Parser.prototype.parse=function(e){return er.parse(e,this.scope)},er.expr.Parser.prototype.eval=function(e){var r=er.parse(e,this.scope);return r.eval()},er.expr.Parser.prototype.get=function(e){return this.scope.get(e)},er.expr.Parser.prototype.set=function(e,r){this.scope.set(e,r)},er.expr.Parser.prototype.remove=function(e){this.scope.remove(e)},er.expr.Parser.prototype.clear=function(){this.scope.clear()},er.abs=function(e){if(1!=arguments.length)throw O("abs",arguments.length,1);if(g(e))return Math.abs(e);if(e instanceof r)return Math.sqrt(e.re*e.re+e.im*e.im);if(Array.isArray(e)||e instanceof n)return rr.map(e,er.abs);if(e.valueOf()!==e)return er.abs(e.valueOf());throw E("abs",e)},er.add=function(e,t){if(2!=arguments.length)throw O("add",arguments.length,2);if(g(e)){if(g(t))return e+t;if(t instanceof r)return r.create(e+t.re,t.im)}else if(e instanceof r){if(g(t))return r.create(e.re+t,e.im);if(t instanceof r)return r.create(e.re+t.re,e.im+t.im)}else if(e instanceof w&&t instanceof w){if(!e.equalBase(t))throw new Error("Units do not match");if(null==e.value)throw new Error("Unit on left hand side of operator + has an undefined value");if(null==t.value)throw new Error("Unit on right hand side of operator + has an undefined value");var a=e.clone();return a.value+=t.value,a.fixPrefix=!1,a}if(x(e)||x(t))return e+t;if(Array.isArray(e)||e instanceof n||Array.isArray(t)||t instanceof n)return rr.map2(e,t,er.add);if(e.valueOf()!==e||t.valueOf()!==t)return er.add(e.valueOf(),t.valueOf());throw E("add",e,t)},er.ceil=function(e){if(1!=arguments.length)throw O("ceil",arguments.length,1);if(g(e))return Math.ceil(e);if(e instanceof r)return r.create(Math.ceil(e.re),Math.ceil(e.im));if(Array.isArray(e)||e instanceof n)return rr.map(e,er.ceil);if(e.valueOf()!==e)return er.ceil(e.valueOf());throw E("ceil",e)},er.cube=function(e){if(1!=arguments.length)throw O("cube",arguments.length,1);if(g(e))return e*e*e;if(e instanceof r)return er.multiply(er.multiply(e,e),e);if(Array.isArray(e)||e instanceof n)return rr.map(e,er.cube);if(e.valueOf()!==e)return er.cube(e.valueOf());throw E("cube",e)},er.divide=function(e,t){if(2!=arguments.length)throw O("divide",arguments.length,2);if(g(e)){if(g(t))return e/t;if(t instanceof r)return L(new r(e,0),t)}if(e instanceof r){if(g(t))return L(e,new r(t,0));if(t instanceof r)return L(e,t)}if(e instanceof w&&g(t)){var a=e.clone();return a.value/=t,a}if(Array.isArray(e)||e instanceof n)return Array.isArray(t)||t instanceof n?er.multiply(e,er.inv(t)):rr.map2(e,t,er.divide);if(Array.isArray(t)||t instanceof n)return er.multiply(e,er.inv(t));if(e.valueOf()!==e||t.valueOf()!==t)return er.divide(e.valueOf(),t.valueOf());throw E("divide",e,t)},er.edivide=function(e,r){if(2!=arguments.length)throw O("edivide",arguments.length,2);return rr.deepMap2(e,r,er.divide)},er.emultiply=function(e,r){if(2!=arguments.length)throw O("emultiply",arguments.length,2);return rr.deepMap2(e,r,er.multiply)},er.epow=function(e,r){if(2!=arguments.length)throw O("epow",arguments.length,2);return rr.deepMap2(e,r,er.pow)},er.equal=function sr(e,t){if(2!=arguments.length)throw O("equal",arguments.length,2);if(g(e)){if(g(t))return e==t;if(t instanceof r)return e==t.re&&0==t.im}if(e instanceof r){if(g(t))return e.re==t&&0==e.im;if(t instanceof r)return e.re==t.re&&e.im==t.im}if(e instanceof w&&t instanceof w){if(!e.equalBase(t))throw new Error("Cannot compare units with different base");return e.value==t.value}if(x(e)||x(t))return e==t;if(Array.isArray(e)||e instanceof n||Array.isArray(t)||t instanceof n)return rr.map2(e,t,er.equal);if(e.valueOf()!==e||t.valueOf()!==t)return sr(e.valueOf(),t.valueOf());throw E("equal",e,t)},er.exp=function(e){if(1!=arguments.length)throw O("exp",arguments.length,1);if(g(e))return Math.exp(e);if(e instanceof r){var t=Math.exp(e.re);return r.create(t*Math.cos(e.im),t*Math.sin(e.im))}if(Array.isArray(e)||e instanceof n)return rr.map(e,er.exp);if(e.valueOf()!==e)return er.exp(e.valueOf());throw E("exp",e)},er.fix=function(e){if(1!=arguments.length)throw O("fix",arguments.length,1);if(g(e))return e>0?Math.floor(e):Math.ceil(e);if(e instanceof r)return r.create(e.re>0?Math.floor(e.re):Math.ceil(e.re),e.im>0?Math.floor(e.im):Math.ceil(e.im));if(Array.isArray(e)||e instanceof n)return rr.map(e,er.fix);if(e.valueOf()!==e)return er.fix(e.valueOf());throw E("fix",e)},er.floor=function(e){if(1!=arguments.length)throw O("floor",arguments.length,1);if(g(e))return Math.floor(e);if(e instanceof r)return r.create(Math.floor(e.re),Math.floor(e.im));if(Array.isArray(e)||e instanceof n)return rr.map(e,er.floor);if(e.valueOf()!==e)return er.floor(e.valueOf());throw E("floor",e)},er.gcd=function(){var e,r=arguments[0],t=arguments[1];if(2==arguments.length){if(g(r)&&g(t)){if(!v(r)||!v(t))throw new Error("Parameters in function gcd must be integer numbers");for(;0!=t;)e=t,t=r%e,r=e;return Math.abs(r)}if(Array.isArray(r)||r instanceof n||Array.isArray(t)||t instanceof n)return rr.map2(r,t,er.gcd);if(r.valueOf()!==r||t.valueOf()!==t)return er.gcd(r.valueOf(),t.valueOf());throw E("gcd",r,t)}if(arguments.length>2){for(var a=1;at;if(t instanceof r)return e>er.abs(t)}if(e instanceof r){if(g(t))return er.abs(e)>t;if(t instanceof r)return er.abs(e)>er.abs(t)}if(e instanceof w&&t instanceof w){if(!e.equalBase(t))throw new Error("Cannot compare units with different base");return e.value>t.value}if(x(e)||x(t))return e>t;if(Array.isArray(e)||e instanceof n||Array.isArray(t)||t instanceof n)return rr.map2(e,t,er.larger);if(e.valueOf()!==e||t.valueOf()!==t)return er.larger(e.valueOf(),t.valueOf());throw E("larger",e,t)},er.largereq=function(e,t){if(2!=arguments.length)throw O("largereq",arguments.length,2);if(g(e)){if(g(t))return e>=t;if(t instanceof r)return e>=er.abs(t)}if(e instanceof r){if(g(t))return er.abs(e)>=t;if(t instanceof r)return er.abs(e)>=er.abs(t)}if(e instanceof w&&t instanceof w){if(!e.equalBase(t))throw new Error("Cannot compare units with different base");return e.value>=t.value}if(x(e)||x(t))return e>=t;if(Array.isArray(e)||e instanceof n||Array.isArray(t)||t instanceof n)return rr.map2(e,t,er.largereq);if(e.valueOf()!==e||t.valueOf()!==t)return er.largereq(e.valueOf(),t.valueOf());throw E("largereq",e,t)},er.lcm=function(){var e,r=arguments[0],t=arguments[1];if(2==arguments.length){if(g(r)&&g(t)){if(!v(r)||!v(t))throw new Error("Parameters in function lcm must be integer numbers");for(var a=r*t;0!=t;)e=t,t=r%e,r=e;return Math.abs(a/r)}if(Array.isArray(r)||r instanceof n||Array.isArray(t)||t instanceof n)return rr.map2(r,t,er.lcm);if(r.valueOf()!==r||t.valueOf()!==t)return er.lcm(r.valueOf(),t.valueOf());throw E("lcm",r,t)}if(arguments.length>2){for(var i=1;i=0?Math.log(e):er.log(new r(e,0));if(e instanceof r)return r.create(Math.log(Math.sqrt(e.re*e.re+e.im*e.im)),Math.atan2(e.im,e.re));if(Array.isArray(e)||e instanceof n)return rr.map(e,er.log);if(e.valueOf()!==e)return er.log(e.valueOf());throw E("log",e)}if(2==arguments.length)return er.divide(er.log(e),er.log(t));throw O("log",arguments.length,1,2)},er.log10=function(e){if(1!=arguments.length)throw O("log10",arguments.length,1);if(g(e))return e>=0?Math.log(e)/Math.LN10:er.log10(new r(e,0));if(e instanceof r)return r.create(Math.log(Math.sqrt(e.re*e.re+e.im*e.im))/Math.LN10,Math.atan2(e.im,e.re)/Math.LN10);if(Array.isArray(e)||e instanceof n)return rr.map(e,er.log10);if(e.valueOf()!==e)return er.log10(e.valueOf());throw E("log10",e)},er.mod=function(e,r){if(2!=arguments.length)throw O("mod",arguments.length,2);if(g(e)&&g(r))return I(e,r);if(Array.isArray(e)||e instanceof n||Array.isArray(r)||r instanceof n)return rr.map2(e,r,er.mod);if(e.valueOf()!==e||r.valueOf()!==r)return er.mod(e.valueOf(),r.valueOf());throw E("mod",e,r)},er.multiply=function ur(e,t){if(2!=arguments.length)throw O("multiply",arguments.length,2);if(g(e)){if(g(t))return e*t;if(t instanceof r)return _(new r(e,0),t);if(t instanceof w)return o=t.clone(),o.value*=e,o}else if(e instanceof r){if(g(t))return _(e,new r(t,0));if(t instanceof r)return _(e,t)}else if(e instanceof w){if(g(t))return o=e.clone(),o.value*=t,o}else{if(Array.isArray(e)){if(Array.isArray(t)){var a=rr.size(e),i=rr.size(t);if(2!=a.length)throw new Error("Can only multiply a 2 dimensional matrix (A has "+a.length+" dimensions)");if(2!=i.length)throw new Error("Can only multiply a 2 dimensional matrix (B has "+i.length+" dimensions)");if(a[1]!=i[0])throw new RangeError("Dimensions mismatch in multiplication. Columns of A must match rows of B (A is "+a[0]+"x"+a[1]+", B is "+i[0]+"x"+i[1]+", "+i[1]+" != "+i[0]+")");for(var o=[],s=a[0],u=i[1],f=a[1],ur=er.multiply,l=er.add,c=0;s>c;c++){o[c]=[];for(var m=0;u>m;m++){for(var h=null,p=0;f>p;p++){var v=ur(e[c][p],t[p][m]);h=null==h?v:l(h,v)}o[c][m]=h}}return o}return t instanceof n?new n(er.multiply(e.valueOf(),t.valueOf())):rr.map2(e,t,er.multiply)}if(e instanceof n)return new n(er.multiply(e.valueOf(),t.valueOf()))}if(Array.isArray(t))return rr.map2(e,t,er.multiply);if(t instanceof n)return new n(er.multiply(e.valueOf(),t.valueOf()));if(e.valueOf()!==e||t.valueOf()!==t)return er.multiply(e.valueOf(),t.valueOf());throw E("multiply",e,t)},er.pow=function(e,t){if(2!=arguments.length)throw O("pow",arguments.length,2);if(g(e)){if(g(t))return v(t)||e>=0?Math.pow(e,t):P(new r(e,0),new r(t,0));if(t instanceof r)return P(new r(e,0),t)}else if(e instanceof r){if(g(t))return P(e,new r(t,0));if(t instanceof r)return P(e,t)}else{if(Array.isArray(e)){if(!g(t)||!v(t)||0>t)throw new TypeError("For A^b, b must be a positive integer (value is "+t+")");var a=rr.size(e);if(2!=a.length)throw new Error("For A^b, A must be 2 dimensional (A has "+a.length+" dimensions)");if(a[0]!=a[1])throw new Error("For A^b, A must be square (size is "+a[0]+"x"+a[1]+")");if(0==t)return er.eye(a[0]);for(var i=e,o=1;t>o;o++)i=er.multiply(e,i);return i}if(e instanceof n)return new n(er.pow(e.valueOf(),t))}if(e.valueOf()!==e||t.valueOf()!==t)return er.pow(e.valueOf(),t.valueOf());throw E("pow",e,t)},er.round=function(e,t){if(1!=arguments.length&&2!=arguments.length)throw O("round",arguments.length,1,2);if(void 0==t){if(g(e))return Math.round(e);if(e instanceof r)return r.create(Math.round(e.re),Math.round(e.im));if(Array.isArray(e)||e instanceof n)return rr.map(e,er.round);if(e.valueOf()!==e)return er.round(e.valueOf());throw E("round",e)}if(!g(t))throw new TypeError("Number of decimals in function round must be an integer");if(t!==Math.round(t))throw new TypeError("Number of decimals in function round must be integer");if(0>t||t>9)throw new Error("Number of decimals in function round must be in te range of 0-9");if(g(e))return B(e,t);if(e instanceof r)return r.create(B(e.re,t),B(e.im,t));if(Array.isArray(e)||e instanceof n||Array.isArray(t)||t instanceof n)return rr.map2(e,t,er.round);if(e.valueOf()!==e||t.valueOf()!==t)return er.round(e.valueOf(),t.valueOf());throw E("round",e,t)},er.sign=function fr(e){if(1!=arguments.length)throw O("sign",arguments.length,1);if(g(e)){var fr;return fr=e>0?1:0>e?-1:0}if(e instanceof r){var t=Math.sqrt(e.re*e.re+e.im*e.im);return r.create(e.re/t,e.im/t)}if(Array.isArray(e)||e instanceof n)return rr.map(e,er.sign);if(e.valueOf()!==e)return er.sign(e.valueOf());throw E("sign",e)},er.smaller=function(e,t){if(2!=arguments.length)throw O("smaller",arguments.length,2);if(g(e)){if(g(t))return t>e;if(t instanceof r)return ee;if(Array.isArray(e)||e instanceof n||Array.isArray(t)||t instanceof n)return rr.map2(e,t,er.smaller);if(e.valueOf()!==e||t.valueOf()!==t)return er.smaller(e.valueOf(),t.valueOf());throw E("smaller",e,t)},er.smallereq=function(e,t){if(2!=arguments.length)throw O("smallereq",arguments.length,2);if(g(e)){if(g(t))return t>=e;if(t instanceof r)return e<=er.abs(t)}if(e instanceof r){if(g(t))return er.abs(e)<=t;if(t instanceof r)return er.abs(e)<=er.abs(t)}if(e instanceof w&&t instanceof w){if(!e.equalBase(t))throw new Error("Cannot compare units with different base");return e.value<=t.value}if(x(e)||x(t))return t>=e;if(Array.isArray(e)||e instanceof n||Array.isArray(t)||t instanceof n)return rr.map2(e,t,er.smallereq);if(e.valueOf()!==e||t.valueOf()!==t)return er.smallereq(e.valueOf(),t.valueOf());throw E("smallereq",e,t)},er.sqrt=function(e){if(1!=arguments.length)throw O("sqrt",arguments.length,1);if(g(e))return e>=0?Math.sqrt(e):er.sqrt(new r(e,0));if(e instanceof r){var t=Math.sqrt(e.re*e.re+e.im*e.im);return e.im>=0?r.create(.5*Math.sqrt(2*(t+e.re)),.5*Math.sqrt(2*(t-e.re))):r.create(.5*Math.sqrt(2*(t+e.re)),-.5*Math.sqrt(2*(t-e.re)))}if(Array.isArray(e)||e instanceof n)return rr.map(e,er.sqrt);if(e.valueOf()!==e)return er.sqrt(e.valueOf());throw E("sqrt",e)},er.square=function(e){if(1!=arguments.length)throw O("square",arguments.length,1);if(g(e))return e*e;if(e instanceof r)return er.multiply(e,e);if(Array.isArray(e)||e instanceof n)return rr.map(e,er.square);if(e.valueOf()!==e)return er.square(e.valueOf());throw E("square",e)},er.subtract=function(e,t){if(2!=arguments.length)throw O("subtract",arguments.length,2);if(g(e)){if(g(t))return e-t;if(t instanceof r)return r.create(e-t.re,-t.im)}else if(e instanceof r){if(g(t))return r.create(e.re-t,e.im);if(t instanceof r)return r.create(e.re-t.re,e.im-t.im)}else if(e instanceof w&&t instanceof w){if(!e.equalBase(t))throw new Error("Units do not match");if(null==e.value)throw new Error("Unit on left hand side of operator - has an undefined value");if(null==t.value)throw new Error("Unit on right hand side of operator - has an undefined value");var a=e.clone();return a.value-=t.value,a.fixPrefix=!1,a}if(Array.isArray(e)||e instanceof n||Array.isArray(t)||t instanceof n)return rr.map2(e,t,er.subtract);if(e.valueOf()!==e||t.valueOf()!==t)return er.subtract(e.valueOf(),t.valueOf());throw E("subtract",e,t)},er.unary=function(e){if(1!=arguments.length)throw O("unary",arguments.length,1);if(g(e))return-e;if(e instanceof r)return r.create(-e.re,-e.im);if(e instanceof w){var t=e.clone();return t.value=-e.value,t}if(Array.isArray(e)||e instanceof n)return rr.map(e,er.unary);if(e.valueOf()!==e)return er.unary(e.valueOf());throw E("unary",e)},er.unaryminus=function(){throw new Error("Function unaryminus is deprecated, use unary instead")},er.unequal=function(e,t){if(2!=arguments.length)throw O("unequal",arguments.length,2);if(g(e)){if(g(t))return e!=t;if(t instanceof r)return e!=t.re||0!=t.im}if(e instanceof r){if(g(t))return e.re!=t||0!=e.im;if(t instanceof r)return e.re!=t.re||e.im!=t.im}if(e instanceof w&&t instanceof w){if(!e.equalBase(t))throw new Error("Cannot compare units with different base");return e.value!=t.value}if(x(e)||x(t))return e!=t;if(Array.isArray(e)||e instanceof n||Array.isArray(t)||t instanceof n)return rr.map2(e,t,er.unequal);if(e.valueOf()!==e||t.valueOf()!==t)return er.unequal(e.valueOf(),t.valueOf());throw E("unequal",e,t)},er.xgcd=function lr(e,r){if(2==arguments.length){if(g(e)&&g(r)){if(!v(e)||!v(r))throw new Error("Parameters in function xgcd must be integer numbers");if(0==r)return[e,1,0];var t=lr(r,e%r),n=t[0],a=t[1],i=t[2];return[n,i,a-i*Math.floor(e/r)]}throw E("xgcd",e,r)}throw new SyntaxError("Function xgcd expects two arguments")},er.arg=function(e){if(1!=arguments.length)throw O("arg",arguments.length,1);return g(e)?Math.atan2(0,e):e instanceof r?Math.atan2(e.im,e.re):Array.isArray(e)||e instanceof n?rr.map(e,er.arg):e.valueOf()!==e?er.arg(e.valueOf()):er.atan2(0,e)},er.conj=function(e){if(1!=arguments.length)throw O("conj",arguments.length,1);return g(e)?e:e instanceof r?r.create(e.re,-e.im):Array.isArray(e)||e instanceof n?rr.map(e,er.conj):e.valueOf()!==e?er.conj(e.valueOf()):clone(e)},er.im=function(e){if(1!=arguments.length)throw O("im",arguments.length,1);return g(e)?0:e instanceof r?e.im:Array.isArray(e)||e instanceof n?rr.map(e,er.im):e.valueOf()!==e?er.im(e.valueOf()):0},er.re=function(e){if(1!=arguments.length)throw O("re",arguments.length,1);return g(e)?e:e instanceof r?e.re:Array.isArray(e)||e instanceof n?rr.map(e,er.re):e.valueOf()!==e?er.re(e.valueOf()):er.clone(e)},er["boolean"]=function(e){if(1!=arguments.length)throw O("boolean",arguments.length,0,1);if("true"===e||e===!0)return!0;if("false"===e||e===!1)return!1;if(g(e))return 0!==e;if(x(e)){var r=e.toLowerCase();if("true"===r)return!0;if("false"===r)return!1;var t=Number(e);if(""!=e&&!isNaN(t))return 0!==t}throw new SyntaxError(e.toString()+" is no valid boolean")},er.complex=function(){switch(arguments.length){case 0:return new r(0,0);case 1:var e=arguments[0];if(e instanceof r)return e.clone();if(x(e)){var t=r.parse(e);if(t)return t;throw new SyntaxError('String "'+e+'" is no valid complex number')}throw new TypeError("Two numbers or a single string expected in function complex");case 2:return new r(arguments[0],arguments[1]);default:throw O("complex",arguments.length,0,2)}},er.matrix=function(e){if(arguments.length>1)throw O("matrix",arguments.length,0,1);return new n(e)},er.number=function(e){switch(arguments.length){case 0:return 0;case 1:var r=Number(e);if(isNaN(r)&&(r=Number(e.valueOf())),isNaN(r))throw new SyntaxError(e.toString()+" is no valid number");return r;default:throw O("number",arguments.length,0,1)}},er.parser=function(){return new er.expr.Parser},er.range=function(e){switch(arguments.length){case 1:if(e instanceof d)return e.clone();if(x(e)){var r=d.parse(e);if(r)return r;throw new SyntaxError('String "'+r+'" is no valid range')}throw new TypeError("Two or three numbers or a single string expected in function range");case 2:return new d(arguments[0],null,arguments[1]);case 3:return new d(arguments[0],arguments[1],arguments[2]);default:throw O("range",arguments.length,2,3)}},er.string=function(e){switch(arguments.length){case 0:return"";case 1:return G(e);default:throw O("string",arguments.length,0,1)}},er.unit=function(){switch(arguments.length){case 1:var e=arguments[0];if(e instanceof w)return e.clone();if(x(e)){if(w.isPlainUnit(e))return new w(null,e);var r=w.parse(e);if(r)return r;throw new SyntaxError('String "'+e+'" is no valid unit')}throw new TypeError("A string or a number and string expected in function unit");case 2:return new w(arguments[0],arguments[1]);default:throw O("unit",arguments.length,1,2)}},er.workspace=function(){throw new Error("Workspace is no longer supported, sorry...")},er.concat=function(){var e,r,t=arguments.length,a=-1,i=!1,o=[];for(e=0;t>e;e++){var s=arguments[e];if(s instanceof n&&(i=!0),e==t-1&&g(s)){if(r=a,a=s,!v(a)||0>a)throw new TypeError("Dimension number must be a positive integer (dim = "+a+")");if(e>0&&a>r)throw new RangeError("Dimension out of range ("+a+" > "+r+")")}else{if(!(Array.isArray(s)||s instanceof n))throw E("concat",s);var u=er.clone(s).valueOf(),f=er.size(s).valueOf();if(o[e]=u,r=a,a=f.length-1,e>0&&a!=r)throw new RangeError("Dimension mismatch ("+r+" != "+a+")")}}if(0==o.length)throw new SyntaxError("At least one matrix expected");for(var l=o.shift();o.length;)l=j(l,o.shift(),a,0);return i?new n(l):l},er.det=function(e){if(1!=arguments.length)throw O("det",arguments.length,1);var r=er.size(e).valueOf();switch(r.length){case 0:return er.clone(e);case 1:if(1==r[0])return er.clone(e.valueOf()[0]);throw new RangeError("Matrix must be square (size: "+er.format(r)+")");case 2:var t=r[0],n=r[1];if(t==n)return k(e.valueOf(),t,n);throw new RangeError("Matrix must be square (size: "+er.format(r)+")");default:throw new RangeError("Matrix must be two dimensional (size: "+er.format(r)+")")}},er.diag=function(e,r){var t,a,i,o;if(1!=arguments.length&&2!=arguments.length)throw O("diag",arguments.length,1,2);if(r){if(!g(r)||!v(r))throw new TypeError("Second parameter in function diag must be an integer")}else r=0;var s=r>0?r:0,u=0>r?-r:0;e instanceof n||e instanceof d||(e=new n(e));var f;switch(e.isVector()?(e=e.toVector(),f=[e.length]):f=e.size(),f.length){case 1:a=e.valueOf();var l=new n;for(l.resize([a.length+u,a.length+s]),t=l.valueOf(),o=a.length,i=0;o>i;i++)t[i+u][i+s]=er.clone(a[i]);return l;case 2:for(a=[],t=e.valueOf(),o=Math.min(f[0]-u,f[1]-s),i=0;o>i;i++)a[i]=er.clone(t[i+u][i+s]);return new n(a);default:throw new RangeError("Matrix for function diag must be 2 dimensional")}},er.eye=function(){var e=rr.argsToArray(arguments);if(0==e.length)e=[1,1];else if(1==e.length)e[1]=e[0];else if(e.length>2)throw O("eye",e.length,0,2);var r=e[0],t=e[1];if(!g(r)||!v(r)||1>r)throw new Error("Parameters in function eye must be positive integers");if(t&&(!g(t)||!v(t)||1>t))throw new Error("Parameters in function eye must be positive integers");var a=new n;a.resize(e);for(var i=er.min(e),o=a.valueOf(),s=0;i>s;s++)o[s][s]=1;return a},er.inv=function(e){if(1!=arguments.length)throw O("inv",arguments.length,1);var r=er.size(e).valueOf();switch(r.length){case 0:return er.divide(1,e);case 1:if(1==r[0])return e instanceof n?new n([er.divide(1,e.valueOf()[0])]):[er.divide(1,e[0])];throw new RangeError("Matrix must be square (size: "+er.format(r)+")");case 2:var t=r[0],a=r[1];if(t==a)return e instanceof n?new n(F(e.valueOf(),t,a)):F(e,t,a);throw new RangeError("Matrix must be square (size: "+er.format(r)+")");default:throw new RangeError("Matrix must be two dimensional (size: "+er.format(r)+")")}},er.ones=function(){var e=rr.argsToArray(arguments);0==e.length?e=[1,1]:1==e.length&&(e[1]=e[0]);var r=new n,t=1;return r.resize(e,t),r},er.size=function(e){if(1!=arguments.length)throw O("size",arguments.length,1);if(g(e)||e instanceof r||e instanceof w||null==e)return[];if(x(e))return[e.length];if(Array.isArray(e))return rr.size(e);if(e instanceof n)return new n(e.size());if(e.valueOf()!==e)return er.size(e.valueOf());throw E("size",e)},er.squeeze=function(e){if(1!=arguments.length)throw O("squeeze",arguments.length,1);return Array.isArray(e)?V(er.clone(e)):e instanceof n?er.matrix(V(e.toArray())):Array.isArray(e.valueOf())?V(er.clone(e.valueOf())):er.clone(e)},er.subset=function(){switch(arguments.length){case 2:return H(arguments[0],arguments[1]);case 3:return Y(arguments[0],arguments[1],arguments[2]);default:throw O("subset",arguments.length,2,3)}},er.transpose=function(e){if(1!=arguments.length)throw O("transpose",arguments.length,1);var r=er.size(e).valueOf();switch(r.length){case 0:return er.clone(e);case 1:return er.clone(e);case 2:for(var t,a=r[1],i=r[0],o=e instanceof n,s=e.valueOf(),u=[],f=er.clone,l=0;a>l;l++){t=u[l]=[];for(var c=0;i>c;c++)t[c]=f(s[c][l])}return 0==i&&(u[0]=[]),o?new n(u):u;default:throw new RangeError("Matrix must be two dimensional (size: "+er.format(r)+")")}},er.zeros=function(){var e=rr.argsToArray(arguments);0==e.length?e=[1,1]:1==e.length&&(e[1]=e[0]);var r=new n;return r.resize(e),r},er.factorial=function(e){if(1!=arguments.length)throw O("factorial",arguments.length,1);if(g(e)){if(!v(e)||0>e)throw new TypeError("Positive integer value expected in function factorial");var r=e,t=r;for(r--;r>1;)t*=r,r--;return 0==t&&(t=1),t}if(Array.isArray(e)||e instanceof n)return rr.map(e,er.factorial);if(e.valueOf()!==e)return er.factorial(e.valueOf());throw E("factorial",e)};var ar={uniform:function(){return Math.random},normal:function(){return function(){for(var e,r,t=-1;0>t||t>1;)e=Math.random(),r=Math.random(),t=1/6*Math.pow(-2*Math.log(e),.5)*Math.cos(2*Math.PI*r)+.5;return t}}};er.distribution=function(e){if(!ar.hasOwnProperty(e))throw new Error("unknown distribution "+e);var r=Array.prototype.slice.call(arguments,1),t=ar[e].apply(this,r);return function(e){var r={random:function(r,a,i){if(arguments.length>3)throw O("random",arguments.length,0,3);if(Array.isArray(r)){var o=a,s=i;return void 0===s&&(s=1),void 0===o&&(o=0),new n(t(r,o,s))}if(arguments.length>2)throw O("random",arguments.length,0,2);var o=r,s=a;return void 0===s&&(s=1),void 0===o&&(o=0),o+e()*(s-o)},randomInt:function(e,r){if(arguments.length>2)throw O("randomInt",arguments.length,0,2);return Math.floor(this.random(e,r))},pickRandom:function(e){if(1!==arguments.length)throw O("pickRandom",arguments.length,1);return e[Math.floor(Math.random()*e.length)]}},t=function(e,n,a){var i,o,s=[];if(e=e.slice(0),e.length>1)for(o=0,i=e.shift();i>o;o++)s.push(t(e,n,a));else for(o=0,i=e.shift();i>o;o++)s.push(r.random.call(r,n,a));return s};return r}(t)};var ir=er.distribution("uniform");er.random=ir.random,er.randomInt=ir.randomInt,er.pickRandom=ir.pickRandom,er.randomMatrix=ir.randomMatrix,er.max=function(e){if(0==arguments.length)throw new Error("Function max requires one or more parameters (0 provided)");if(Array.isArray(e)||e instanceof n||e instanceof d){if(arguments.length>1)throw Error("Wrong number of parameters (1 matrix or multiple scalars expected)"); -var r=er.size(e).valueOf();if(1==r.length){if(0==e.length)throw new Error("Cannot calculate max of an empty vector");return Q(e.valueOf())}if(2==r.length){if(0==r[0]||0==r[1])throw new Error("Cannot calculate max of an empty matrix");if(Array.isArray(e))return K(e,r[0],r[1]);if(e instanceof n||e instanceof d)return new n(K(e.valueOf(),r[0],r[1]));throw E("max",e)}throw new RangeError("Cannot calculate max for multi dimensional matrix")}return Q(arguments)},er.min=function(e){if(0==arguments.length)throw new Error("Function min requires one or more parameters (0 provided)");if(Array.isArray(e)||e instanceof n||e instanceof d){if(arguments.length>1)throw Error("Wrong number of parameters (1 matrix or multiple scalars expected)");var r=er.size(e).valueOf();if(1==r.length){if(0==e.length)throw new Error("Cannot calculate min of an empty vector");return Z(e.valueOf())}if(2==r.length){if(0==r[0]||0==r[1])throw new Error("Cannot calculate min of an empty matrix");if(Array.isArray(e))return X(e,r[0],r[1]);if(e instanceof n||e instanceof d)return new n(X(e.valueOf(),r[0],r[1]));throw E("min",e)}throw new RangeError("Cannot calculate min for multi dimensional matrix")}return Z(arguments)},er.acos=function(e){if(1!=arguments.length)throw O("acos",arguments.length,1);if(g(e))return e>=-1&&1>=e?Math.acos(e):er.acos(new r(e,0));if(e instanceof r){var t,a=r.create(e.im*e.im-e.re*e.re+1,-2*e.re*e.im),i=er.sqrt(a);t=i instanceof r?r.create(i.re-e.im,i.im+e.re):r.create(i-e.im,e.re);var o=er.log(t);return o instanceof r?r.create(1.5707963267948966-o.im,o.re):new r(1.5707963267948966,o)}if(Array.isArray(e)||e instanceof n)return rr.map(e,er.acos);if(e.valueOf()!==e)return er.acos(e.valueOf());throw E("acos",e)},er.asin=function(e){if(1!=arguments.length)throw O("asin",arguments.length,1);if(g(e))return e>=-1&&1>=e?Math.asin(e):er.asin(new r(e,0));if(e instanceof r){var t,a=e.re,i=e.im,o=r.create(i*i-a*a+1,-2*a*i),s=er.sqrt(o);t=s instanceof r?r.create(s.re-i,s.im+a):r.create(s-i,a);var u=er.log(t);return u instanceof r?r.create(u.im,-u.re):r.create(0,-u)}if(Array.isArray(e)||e instanceof n)return rr.map(e,er.asin);if(e.valueOf()!==e)return er.asin(e.valueOf());throw E("asin",e)},er.atan=function(e){if(1!=arguments.length)throw O("atan",arguments.length,1);if(g(e))return Math.atan(e);if(e instanceof r){var t=e.re,a=e.im,i=t*t+(1-a)*(1-a),o=r.create((1-a*a-t*t)/i,-2*t/i),s=er.log(o);return s instanceof r?r.create(-.5*s.im,.5*s.re):r.create(0,.5*s)}if(Array.isArray(e)||e instanceof n)return rr.map(e,er.atan);if(e.valueOf()!==e)return er.atan(e.valueOf());throw E("atan",e)},er.atan2=function(e,t){if(2!=arguments.length)throw O("atan2",arguments.length,2);if(g(e)){if(g(t))return Math.atan2(e,t)}else if(e instanceof r&&g(t))return Math.atan2(e.re,t);if(Array.isArray(e)||e instanceof n||Array.isArray(t)||t instanceof n)return rr.map2(e,t,er.atan2);if(t.valueOf()!==t||e.valueOf()!==e)return er.atan2(e.valueOf(),t.valueOf());throw E("atan2",e,t)},er.cos=function(e){if(1!=arguments.length)throw O("cos",arguments.length,1);if(g(e))return Math.cos(e);if(e instanceof r)return r.create(.5*Math.cos(e.re)*(Math.exp(-e.im)+Math.exp(e.im)),.5*Math.sin(e.re)*(Math.exp(-e.im)-Math.exp(e.im)));if(e instanceof w){if(!e.hasBase(w.BASE_UNITS.ANGLE))throw new TypeError("Unit in function cos is no angle");return Math.cos(e.value)}if(Array.isArray(e)||e instanceof n)return rr.map(e,er.cos);if(e.valueOf()!==e)return er.cos(e.valueOf());throw E("cos",e)},er.cot=function(e){if(1!=arguments.length)throw O("cot",arguments.length,1);if(g(e))return 1/Math.tan(e);if(e instanceof r){var t=Math.exp(-4*e.im)-2*Math.exp(-2*e.im)*Math.cos(2*e.re)+1;return r.create(2*Math.exp(-2*e.im)*Math.sin(2*e.re)/t,(Math.exp(-4*e.im)-1)/t)}if(e instanceof w){if(!e.hasBase(w.BASE_UNITS.ANGLE))throw new TypeError("Unit in function cot is no angle");return 1/Math.tan(e.value)}if(Array.isArray(e)||e instanceof n)return rr.map(e,er.cot);if(e.valueOf()!==e)return er.cot(e.valueOf());throw E("cot",e)},er.csc=function(e){if(1!=arguments.length)throw O("csc",arguments.length,1);if(g(e))return 1/Math.sin(e);if(e instanceof r){var t=.25*(Math.exp(-2*e.im)+Math.exp(2*e.im))-.5*Math.cos(2*e.re);return r.create(.5*Math.sin(e.re)*(Math.exp(-e.im)+Math.exp(e.im))/t,.5*Math.cos(e.re)*(Math.exp(-e.im)-Math.exp(e.im))/t)}if(e instanceof w){if(!e.hasBase(w.BASE_UNITS.ANGLE))throw new TypeError("Unit in function csc is no angle");return 1/Math.sin(e.value)}if(Array.isArray(e)||e instanceof n)return rr.map(e,er.csc);if(e.valueOf()!==e)return er.csc(e.valueOf());throw E("csc",e)},er.sec=function(e){if(1!=arguments.length)throw O("sec",arguments.length,1);if(g(e))return 1/Math.cos(e);if(e instanceof r){var t=.25*(Math.exp(-2*e.im)+Math.exp(2*e.im))+.5*Math.cos(2*e.re);return r.create(.5*Math.cos(e.re)*(Math.exp(-e.im)+Math.exp(e.im))/t,.5*Math.sin(e.re)*(Math.exp(e.im)-Math.exp(-e.im))/t)}if(e instanceof w){if(!e.hasBase(w.BASE_UNITS.ANGLE))throw new TypeError("Unit in function sec is no angle");return 1/Math.cos(e.value)}if(Array.isArray(e)||e instanceof n)return rr.map(e,er.sec);if(e.valueOf()!==e)return er.sec(e.valueOf());throw E("sec",e)},er.sin=function(e){if(1!=arguments.length)throw O("sin",arguments.length,1);if(g(e))return Math.sin(e);if(e instanceof r)return r.create(.5*Math.sin(e.re)*(Math.exp(-e.im)+Math.exp(e.im)),.5*Math.cos(e.re)*(Math.exp(e.im)-Math.exp(-e.im)));if(e instanceof w){if(!e.hasBase(w.BASE_UNITS.ANGLE))throw new TypeError("Unit in function cos is no angle");return Math.sin(e.value)}if(Array.isArray(e)||e instanceof n)return rr.map(e,er.sin);if(e.valueOf()!==e)return er.sin(e.valueOf());throw E("sin",e)},er.tan=function(e){if(1!=arguments.length)throw O("tan",arguments.length,1);if(g(e))return Math.tan(e);if(e instanceof r){var t=Math.exp(-4*e.im)+2*Math.exp(-2*e.im)*Math.cos(2*e.re)+1;return r.create(2*Math.exp(-2*e.im)*Math.sin(2*e.re)/t,(1-Math.exp(-4*e.im))/t)}if(e instanceof w){if(!e.hasBase(w.BASE_UNITS.ANGLE))throw new TypeError("Unit in function tan is no angle");return Math.tan(e.value)}if(Array.isArray(e)||e instanceof n)return rr.map(e,er.tan);if(e.valueOf()!==e)return er.tan(e.valueOf());throw E("tan",e)},er["in"]=function(e,r){if(2!=arguments.length)throw O("in",arguments.length,2);if(e instanceof w&&(r instanceof w||x(r)))return e["in"](r);if(Array.isArray(e)||e instanceof n||Array.isArray(r)||r instanceof n)return rr.map2(e,r,er["in"]);if(e.valueOf()!==e||r.valueOf()!==r)return er["in"](e.valueOf(),r.valueOf());throw E("in",e,r)},er.clone=function(r){if(1!=arguments.length)throw O("clone",arguments.length,1);if(null==r)return r;if("function"==typeof r.clone)return r.clone();if(g(r)||x(r)||e(r))return r;if(Array.isArray(r)){var t=er.clone;return r.map(function(e){return t(e)})}if(r instanceof Object)return rr.mapObject(r,er.clone);throw E("clone",r)},er.eval=function(e,r){if(1!=arguments.length&&2!=arguments.length)throw O("eval",arguments.length,1,2);var t;if(t=r?r instanceof er.expr.Scope?r:new er.expr.Scope(r):new er.expr.Scope,x(e)){var a=er.parse(e,t);return a.eval()}if(Array.isArray(e)||e instanceof n)return rr.map(e,function(e){var r=er.parse(e,t);return r.eval()});throw new TypeError("String or matrix expected")},er.format=function(e,r){var t=arguments.length;if(1!=t&&2!=t)throw O("format",t,1,2);if(1==t){var n=arguments[0];return g(n)?rr.formatNumber(n,er.options.precision):Array.isArray(n)?rr.formatArray(n):x(n)?'"'+n+'"':n instanceof Object?n.toString():String(n)}if(!x(e))throw new TypeError("String expected as first parameter in function format");if(!(r instanceof Object))throw new TypeError("Object expected as first parameter in function format");return e.replace(/\$([\w\.]+)/g,function(e,t){for(var n=t.split("."),a=r[n.shift()];n.length&&void 0!=a;){var i=n.shift();a=i?a[i]:a+"."}return void 0!=a?a:e})},er.help=function(e){if(1!=arguments.length)throw new SyntaxError("Wrong number of arguments in function help ("+arguments.length+" provided, 1 expected)");var r=null;if(e instanceof String||"string"==typeof e)r=e;else{var n;for(n in er)if(er.hasOwnProperty(n)&&e===er[n]){r=n;break}if(!r)for(n in er.type)if(er.type.hasOwnProperty(n)&&e===er.type[n]){r=n;break}}if(r){var a=er.docs[r];if(!a)throw new Error('No documentation found on "'+r+'"');return new t(a)}throw new Error('Could not find search term "'+e+'"')},er["import"]=function(e,r){var t,n={override:!1,wrap:!0};if(r&&r instanceof Object&&rr.extend(n,r),x(e)){if("undefined"==typeof require)throw new Error("Cannot load file: require not available.");var a=require(e);er["import"](a)}else if(J(e)){if(t=e.name,!t)throw new Error("Cannot import an unnamed function or object");(n.override||void 0===er[t])&&$(t,e,n)}else if(e instanceof Object)for(t in e)if(e.hasOwnProperty(t)){var i=e[t];J(i)?$(t,i,n):er["import"](i)}},function(){function e(){tr=0,nr=J.charAt(0)}function t(){tr++,nr=J.charAt(tr)}function a(){return J.charAt(tr+1)}function i(){for(ir=Z.NULL,ar="";" "==nr||" "==nr;)t();if("#"==nr)for(;"\n"!=nr&&""!=nr;)t();if(""==nr)return ir=Z.DELIMITER,void 0;var e=nr+a();if(X[e])return ir=Z.DELIMITER,ar=e,t(),t(),void 0;if(X[nr])return ir=Z.DELIMITER,ar=nr,t(),void 0;if(s(nr)){if(ir=Z.NUMBER,"."==nr)ar+=nr,t(),u(nr)||(ir=Z.UNKNOWN);else{for(;u(nr);)ar+=nr,t();"."==nr&&(ar+=nr,t())}for(;u(nr);)ar+=nr,t();if("E"==nr||"e"==nr)for(ar+=nr,t(),("+"==nr||"-"==nr)&&(ar+=nr,t()),u(nr)||(ir=Z.UNKNOWN);u(nr);)ar+=nr,t()}else{if(!o(nr)){for(ir=Z.UNKNOWN;""!=nr;)ar+=nr,t();throw W('Syntax error in part "'+ar+'"')}for(ir=Z.SYMBOL;o(nr)||u(nr);)ar+=nr,t()}}function o(e){return e>="a"&&"z">=e||e>="A"&&"Z">=e||"_"==e}function s(e){return e>="0"&&"9">=e||"."==e}function u(e){return e>="0"&&"9">=e}function f(r){e(),i();var t;if(t=""==ar?new N(void 0):l(r),""!=ar)throw ir==Z.DELIMITER?K("Unknown operator "+ar):W('Unexpected part "'+ar+'"');return t}function l(e){var r,t,n;for("\n"!=ar&&";"!=ar&&""!=ar&&(r=c(e));"\n"==ar||";"==ar;)t||(t=new z,r&&(n=";"!=ar,t.add(r,n))),i(),"\n"!=ar&&";"!=ar&&""!=ar&&(r=c(e),n=";"!=ar,t.add(r,n));return t?t:(r||(r=c(e)),r)}function c(e){var r=m(e),t="ans";return new R(t,r,e)}function m(e){if(ir==Z.SYMBOL&&"function"==ar){if(i(),ir!=Z.SYMBOL)throw W("Function name expected");var r=ar;if(i(),"("!=ar)throw W("Opening parenthesis ( expected");for(var t=e.createSubScope(),n=[];;){if(i(),ir!=Z.SYMBOL)throw W("Variable name expected");if(n.push(ar),i(),","!=ar){if(")"==ar)break;throw W('Comma , or closing parenthesis ) expected"')}}if(i(),"="!=ar)throw W("Equal sign = expected");i();var a=h(t);return new U(r,n,a,t,e)}return h(e)}function h(e){var r,t,n,a,o=p(e);if("="==ar){if(o instanceof S)return i(),r=o.name,t=null,a=h(e),new R(r,a,e);if(o instanceof T&&o.object instanceof S)return i(),r=o.object.name,t=o.params,n=o.paramScopes,a=h(e),new C(r,t,n,a,e);throw W("Symbol expected at the left hand side of assignment operator =")}return o}function p(e){var r,t,n,a=[];if(r=":"==ar?new N(0):g(e),":"==ar){for(a.push(r);":"==ar;)i(),")"==ar||","==ar||""==ar?a.push(new S("end",e)):a.push(g(e));a.length&&(t="range",n=er.range,r=new M(t,n,a))}return r}function g(e){var r,t,n,a,o;for(r=v(e),t={"in":"in"};void 0!==t[ar];)n=ar,a=er[t[n]],i(),o=[r,v(e)],r=new M(n,a,o);return r}function v(e){var r=d(e);return r}function d(e){var r,t,n,a,o;for(r=y(e),t={"==":"equal","!=":"unequal","<":"smaller",">":"larger","<=":"smallereq",">=":"largereq"};void 0!==t[ar];)n=ar,a=er[t[n]],i(),o=[r,y(e)],r=new M(n,a,o);return r}function y(e){var r,t,n,a,o;for(r=b(e),t={"+":"add","-":"subtract"};void 0!==t[ar];)n=ar,a=er[t[n]],i(),o=[r,b(e)],r=new M(n,a,o);return r}function b(e){var r,t,n,a,o;for(r=E(e),t={"*":"multiply",".*":"emultiply","/":"divide","./":"edivide","%":"mod",mod:"mod"};void 0!==t[ar];)n=ar,a=er[t[n]],i(),o=[r,E(e)],r=new M(n,a,o);return r}function E(e){var r,t,n;return"-"==ar?(r=ar,t=er.unary,i(),n=[E(e)],new M(r,t,n)):A(e)}function A(e){var r,t,n,a,o,s,u;for(n=[L(e)],a=[];"^"==ar||".^"==ar;)a.push(ar),i(),n.push(L(e));for(r=n.pop();n.length;)t=n.pop(),o=a.pop(),s="^"==o?er.pow:er.epow,u=[t,r],r=new M(o,s,u);return r}function L(e){var r,t,n,a;for(r=I(e);"!"==ar;)t=ar,n=er.factorial,i(),a=[r],r=new M(t,n,a);return r}function I(e){var r,t,n,a;for(r=_(e);"'"==ar;)t=ar,n=er.transpose,i(),a=[r],r=new M(t,n,a);return r}function _(e){var r,t,n,a;if(ir==Z.SYMBOL&&$[ar]){if(a=$[ar],i(),"("==ar){if(r=[],t=[],i(),")"!=ar)for(n=e.createSubScope(),t.push(n),r.push(p(n));","==ar;)i(),n=e.createSubScope(),t.push(n),r.push(p(n));if(")"!=ar)throw W("Parenthesis ) expected");i()}return new a(r,t)}return P(e)}function P(e){var r,t;return ir==Z.SYMBOL?(t=ar,i(),r=new S(t,e),B(e,r)):G(e)}function B(e,r){for(var t,n,a;"("==ar;){if(t=[],n=[],i(),")"!=ar)for(a=e.createSubScope(),n.push(a),t.push(p(a));","==ar;)i(),a=e.createSubScope(),n.push(a),t.push(p(a));if(")"!=ar)throw W("Parenthesis ) expected");i(),r=new T(r,t,n)}return r}function G(e){var r,n,a;if('"'==ar){for(n="",a="";""!=nr&&('"'!=nr||"\\"==a);)n+=nr,a=nr,t();if(i(),'"'!=ar)throw W('End of string " expected');return i(),r=new N(n),r=B(e,r)}return j(e)}function j(e){var r,t,n,a,o,s;if("["==ar){for(i();"\n"==ar;)i();if("]"!=ar){for(t=[],n=0,a=0,t[0]=[h(e)];","==ar||";"==ar;){for(","==ar?a++:(n++,a=0,t[n]=[]),i();"\n"==ar;)i();for(t[n][a]=h(e);"\n"==ar;)i()}for(o=t.length,s=t.length>0?t[0].length:0,n=1;o>n;n++)if(t[n].length!=s)throw K("Number of columns must match ("+t[n].length+" != "+s+")");if("]"!=ar)throw W("End of matrix ] expected");i(),r=new q(t)}else i(),r=new q([[]]);return r=B(e,r)}return k(e)}function k(e){var t,n,a;if(ir==Z.NUMBER){if(a="."==ar?0:Number(ar),i(),ir==Z.SYMBOL){if("i"==ar||"I"==ar)return n=new r(0,a),i(),new N(n);if(w.isPlainUnit(ar))return n=new w(a,ar),i(),new N(n);throw Q('Unknown unit "'+ar+'"')}return t=new N(a),t=B(e,t)}return F(e)}function F(e){var r;if("("==ar){if(i(),r=h(e),")"!=ar)throw W("Parenthesis ) expected");return i(),r=B(e,r)}return V(e)}function V(){throw""==ar?W("Unexpected end of expression"):W("Value expected")}function H(){return void 0}function D(){return tr-ar.length+1}function Y(e){var r=H(),t=D();return void 0===r?void 0===t?e:e+" (char "+t+")":e+" (line "+r+", char "+t+")"}function W(e){return new SyntaxError(Y(e))}function Q(e){return new TypeError(Y(e))}function K(e){return new Error(Y(e))}er.parse=function(e,r){if(1!=arguments.length&&2!=arguments.length)throw O("parse",arguments.length,1,2);var t;if(t=r?r instanceof er.expr.Scope?r:new er.expr.Scope(r):new er.expr.Scope,x(e))return J=e||"",f(t);if(Array.isArray(e)||e instanceof n)return rr.map(e,function(e){return J=e||"",f(t)});throw new TypeError("String or matrix expected")};var Z={NULL:0,DELIMITER:1,NUMBER:2,SYMBOL:3,UNKNOWN:4},X={",":!0,"(":!0,")":!0,"[":!0,"]":!0,'"':!0,"\n":!0,";":!0,"+":!0,"-":!0,"*":!0,".*":!0,"/":!0,"./":!0,"%":!0,"^":!0,".^":!0,"!":!0,"'":!0,"=":!0,":":!0,"==":!0,"!=":!0,"<":!0,">":!0,"<=":!0,">=":!0},$=er.expr.node.handlers,J="",tr=0,nr="",ar="",ir=Z.NULL}(),er.select=function(e){return new er.type.Selector(e)},er["typeof"]=function(e){if(1!=arguments.length)throw O("typeof",arguments.length,1);var r,t=typeof e;if("object"==t){if(null==e)return"null";if(e instanceof Boolean)return"boolean";if(e instanceof Number)return"number";if(e instanceof String)return"string";if(Array.isArray(e))return"array";if(e instanceof Date)return"date";if(e.constructor){for(r in er)if(er.hasOwnProperty(r)&&e.constructor==er[r])return r.toLowerCase();for(r in er.type)if(er.type.hasOwnProperty(r)&&e.constructor==er.type[r])return r.toLowerCase();if(e.constructor.name)return e.constructor.name.toLowerCase()}}return t},er.docs.Infinity={name:"Infinity",category:"Constants",syntax:["Infinity"],description:"Infinity, a number which is larger than the maximum number that can be handled by a floating point number.",examples:["Infinity","1 / 0"],seealso:[]},er.docs.LN10={name:"LN10",category:"Constants",syntax:["LN10"],description:"Returns the natural logarithm of 10, approximately equal to 2.302",examples:["LN10","log(10)"],seealso:[]},er.docs.LN2={name:"LN2",category:"Constants",syntax:["LN2"],description:"Returns the natural logarithm of 2, approximately equal to 0.693",examples:["LN2","log(2)"],seealso:[]},er.docs.LOG10E={name:"LOG10E",category:"Constants",syntax:["LOG10E"],description:"Returns the base-10 logarithm of E, approximately equal to 0.434",examples:["LOG10E","log(e, 10)"],seealso:[]},er.docs.LOG2E={name:"LOG2E",category:"Constants",syntax:["LOG2E"],description:"Returns the base-2 logarithm of E, approximately equal to 1.442",examples:["LOG2E","log(e, 2)"],seealso:[]},er.docs.NaN={name:"NaN",category:"Constants",syntax:["NaN"],description:"Not a number",examples:["NaN","0 / 0"],seealso:[]},er.docs.SQRT1_2={name:"SQRT1_2",category:"Constants",syntax:["SQRT1_2"],description:"Returns the square root of 1/2, approximately equal to 0.707",examples:["SQRT1_2","sqrt(1/2)"],seealso:[]},er.docs.SQRT2={name:"SQRT2",category:"Constants",syntax:["SQRT2"],description:"Returns the square root of 2, approximately equal to 1.414",examples:["SQRT2","sqrt(2)"],seealso:[]},er.docs.e=er.docs.E={name:"e",category:"Constants",syntax:["e"],description:"Euler's number, the base of the natural logarithm. Approximately equal to 2.71828",examples:["e","e ^ 2","exp(2)","log(e)"],seealso:["exp"]},er.docs["false"]={name:"false",category:"Constants",syntax:["false"],description:"Boolean value false",examples:["false"],seealso:["true"]},er.docs.i={name:"i",category:"Constants",syntax:["i"],description:"Imaginary unit, defined as i*i=-1. A complex number is described as a + b*i, where a is the real part, and b is the imaginary part.",examples:["i","i * i","sqrt(-1)"],seealso:[]},er.docs.pi=er.docs.PI={name:"pi",category:"Constants",syntax:["pi"],description:"The number pi is a mathematical constant that is the ratio of a circle's circumference to its diameter, and is approximately equal to 3.14159",examples:["pi","sin(pi/2)"],seealso:["tau"]},er.docs.tau={name:"tau",category:"Constants",syntax:["pi"],description:"Tau is the ratio constant of a circle's circumference to radius, equal to 2 * pi, approximately 6.2832.",examples:["tau","2 * pi"],seealso:["pi"]},er.docs["true"]={name:"true",category:"Constants",syntax:["true"],description:"Boolean value true",examples:["true"],seealso:["false"]},er.docs.abs={name:"abs",category:"Arithmetic",syntax:["abs(x)"],description:"Compute the absolute value.",examples:["abs(3.5)","abs(-4.2)"],seealso:["sign"]},er.docs.add={name:"add",category:"Operators",syntax:["x + y","add(x, y)"],description:"Add two values.",examples:["2.1 + 3.6","ans - 3.6","3 + 2i",'"hello" + " world"',"3 cm + 2 inch"],seealso:["subtract"]},er.docs.ceil={name:"ceil",category:"Arithmetic",syntax:["ceil(x)"],description:"Round a value towards plus infinity.If x is complex, both real and imaginary part are rounded towards plus infinity.",examples:["ceil(3.2)","ceil(3.8)","ceil(-4.2)"],seealso:["floor","fix","round"]},er.docs.cube={name:"cube",category:"Arithmetic",syntax:["cube(x)"],description:"Compute the cube of a value. The cube of x is x * x * x.",examples:["cube(2)","2^3","2 * 2 * 2"],seealso:["multiply","square","pow"]},er.docs.divide={name:"divide",category:"Operators",syntax:["x / y","divide(x, y)"],description:"Divide two values.",examples:["2 / 3","ans * 3","4.5 / 2","3 + 4 / 2","(3 + 4) / 2","18 km / 4.5"],seealso:["multiply"]},er.docs.edivide={name:"edivide",category:"Operators",syntax:["x ./ y","edivide(x, y)"],description:"divide two values element wise.",examples:["a = [1, 2, 3; 4, 5, 6]","b = [2, 1, 1; 3, 2, 5]","a ./ b"],seealso:["multiply","emultiply","divide"]},er.docs.emultiply={name:"emultiply",category:"Operators",syntax:["x .* y","emultiply(x, y)"],description:"multiply two values element wise.",examples:["a = [1, 2, 3; 4, 5, 6]","b = [2, 1, 1; 3, 2, 5]","a .* b"],seealso:["multiply","divide","edivide"]},er.docs.epow={name:"epow",category:"Operators",syntax:["x .^ y","epow(x, y)"],description:"Calculates the power of x to y element wise.",examples:["a = [1, 2, 3; 4, 5, 6]","a .^ 2"],seealso:["pow"]},er.docs.equal={name:"equal",category:"Operators",syntax:["x == y","equal(x, y)"],description:"Check equality of two values. Returns 1 if the values are equal, and 0 if not.",examples:["2+2 == 3","2+2 == 4","a = 3.2","b = 6-2.8","a == b","50cm == 0.5m"],seealso:["unequal","smaller","larger","smallereq","largereq"]},er.docs.exp={name:"exp",category:"Arithmetic",syntax:["exp(x)"],description:"Calculate the exponent of a value.",examples:["exp(1.3)","e ^ 1.3","log(exp(1.3))","x = 2.4","(exp(i*x) == cos(x) + i*sin(x)) # Euler's formula"],seealso:["square","multiply","log"]},er.docs.fix={name:"fix",category:"Arithmetic",syntax:["fix(x)"],description:"Round a value towards zero.If x is complex, both real and imaginary part are rounded towards zero.",examples:["fix(3.2)","fix(3.8)","fix(-4.2)","fix(-4.8)"],seealso:["ceil","floor","round"]},er.docs.floor={name:"floor",category:"Arithmetic",syntax:["floor(x)"],description:"Round a value towards minus infinity.If x is complex, both real and imaginary part are rounded towards minus infinity.",examples:["floor(3.2)","floor(3.8)","floor(-4.2)"],seealso:["ceil","fix","round"]},er.docs.gcd={name:"gcd",category:"Arithmetic",syntax:["gcd(a, b)","gcd(a, b, c, ...)"],description:"Compute the greatest common divisor.",examples:["gcd(8, 12)","gcd(-4, 6)","gcd(25, 15, -10)"],seealso:["lcm","xgcd"]},er.docs.larger={name:"larger",category:"Operators",syntax:["x > y","larger(x, y)"],description:"Check if value x is larger than y. Returns 1 if x is larger than y, and 0 if not.",examples:["2 > 3","5 > 2*2","a = 3.3","b = 6-2.8","(a > b)","(b < a)","5 cm > 2 inch"],seealso:["equal","unequal","smaller","smallereq","largereq"]},er.docs.largereq={name:"largereq",category:"Operators",syntax:["x >= y","largereq(x, y)"],description:"Check if value x is larger or equal to y. Returns 1 if x is larger or equal to y, and 0 if not.",examples:["2 > 1+1","2 >= 1+1","a = 3.2","b = 6-2.8","(a > b)"],seealso:["equal","unequal","smallereq","smaller","largereq"]},er.docs.lcm={name:"lcm",category:"Arithmetic",syntax:["lcm(x, y)"],description:"Compute the least common multiple.",examples:["lcm(4, 6)","lcm(6, 21)","lcm(6, 21, 5)"],seealso:["gcd"]},er.docs.log={name:"log",category:"Arithmetic",syntax:["log(x)","log(x, base)"],description:"Compute the logarithm of a value. If no base is provided, the natural logarithm of x is calculated. If base if provided, the logarithm is calculated for the specified base. log(x, base) is defined as log(x) / log(base).",examples:["log(3.5)","a = log(2.4)","exp(a)","10 ^ 3","log(1000, 10)","log(1000) / log(10)","b = logb(1024, 2)","2 ^ b"],seealso:["exp","log10"]},er.docs.log10={name:"log10",category:"Arithmetic",syntax:["log10(x)"],description:"Compute the 10-base logarithm of a value.",examples:["log10(1000)","10 ^ 3","log10(0.01)","log(1000) / log(10)","log(1000, 10)"],seealso:["exp","log"]},er.docs.mod={name:"mod",category:"Operators",syntax:["x % y","x mod y","mod(x, y)"],description:"Calculates the modulus, the remainder of an integer division.",examples:["7 % 3","11 % 2","10 mod 4","function isOdd(x) = x % 2","isOdd(2)","isOdd(3)"],seealso:[]},er.docs.multiply={name:"multiply",category:"Operators",syntax:["x * y","multiply(x, y)"],description:"multiply two values.",examples:["2.1 * 3.6","ans / 3.6","2 * 3 + 4","2 * (3 + 4)","3 * 2.1 km"],seealso:["divide"]},er.docs.pow={name:"pow",category:"Operators",syntax:["x ^ y","pow(x, y)"],description:"Calculates the power of x to y, x^y.",examples:["2^3 = 8","2*2*2","1 + e ^ (pi * i)"],seealso:["unequal","smaller","larger","smallereq","largereq"]},er.docs.round={name:"round",category:"Arithmetic",syntax:["round(x)","round(x, n)"],description:"round a value towards the nearest integer.If x is complex, both real and imaginary part are rounded towards the nearest integer. When n is specified, the value is rounded to n decimals.",examples:["round(3.2)","round(3.8)","round(-4.2)","round(-4.8)","round(pi, 3)","round(123.45678, 2)"],seealso:["ceil","floor","fix"]},er.docs.sign={name:"sign",category:"Arithmetic",syntax:["sign(x)"],description:"Compute the sign of a value. The sign of a value x is 1 when x>1, -1 when x<0, and 0 when x=0.",examples:["sign(3.5)","sign(-4.2)","sign(0)"],seealso:["abs"]},er.docs.smaller={name:"smaller",category:"Operators",syntax:["x < y","smaller(x, y)"],description:"Check if value x is smaller than value y. Returns 1 if x is smaller than y, and 0 if not.",examples:["2 < 3","5 < 2*2","a = 3.3","b = 6-2.8","(a < b)","5 cm < 2 inch"],seealso:["equal","unequal","larger","smallereq","largereq"]},er.docs.smallereq={name:"smallereq",category:"Operators",syntax:["x <= y","smallereq(x, y)"],description:"Check if value x is smaller or equal to value y. Returns 1 if x is smaller than y, and 0 if not.",examples:["2 < 1+1","2 <= 1+1","a = 3.2","b = 6-2.8","(a < b)"],seealso:["equal","unequal","larger","smaller","largereq"]},er.docs.sqrt={name:"sqrt",category:"Arithmetic",syntax:["sqrt(x)"],description:"Compute the square root value. If x = y * y, then y is the square root of x.",examples:["sqrt(25)","5 * 5","sqrt(-1)"],seealso:["square","multiply"]},er.docs.square={name:"square",category:"Arithmetic",syntax:["square(x)"],description:"Compute the square of a value. The square of x is x * x.",examples:["square(3)","sqrt(9)","3^2","3 * 3"],seealso:["multiply","pow","sqrt","cube"]},er.docs.subtract={name:"subtract",category:"Operators",syntax:["x - y","subtract(x, y)"],description:"subtract two values.",examples:["5.3 - 2","ans + 2","2/3 - 1/6","2 * 3 - 3","2.1 km - 500m"],seealso:["add"]},er.docs.unary={name:"unary",category:"Operators",syntax:["-x","unary(x)"],description:"Inverse the sign of a value.",examples:["-4.5","-(-5.6)"],seealso:["add","subtract"]},er.docs.unequal={name:"unequal",category:"Operators",syntax:["x != y","unequal(x, y)"],description:"Check unequality of two values. Returns 1 if the values are unequal, and 0 if they are equal.",examples:["2+2 != 3","2+2 != 4","a = 3.2","b = 6-2.8","a != b","50cm != 0.5m","5 cm != 2 inch"],seealso:["equal","smaller","larger","smallereq","largereq"]},er.docs.xgcd={name:"xgcd",category:"Arithmetic",syntax:["xgcd(a, b)"],description:"Calculate the extended greatest common divisor for two values",examples:["xgcd(8, 12)","gcd(8, 12)","xgcd(36163, 21199)"],seealso:["gcd","lcm"]},er.docs.arg={name:"arg",category:"Complex",syntax:["arg(x)"],description:"Compute the argument of a complex value. If x = a+bi, the argument is computed as atan2(b, a).",examples:["arg(2 + 2i)","atan2(3, 2)","arg(2 - 3i)"],seealso:["re","im","conj","abs"]},er.docs.conj={name:"conj",category:"Complex",syntax:["conj(x)"],description:"Compute the complex conjugate of a complex value. If x = a+bi, the complex conjugate is a-bi.",examples:["conj(2 + 3i)","conj(2 - 3i)","conj(-5.2i)"],seealso:["re","im","abs","arg"]},er.docs.im={name:"im",category:"Complex",syntax:["im(x)"],description:"Get the imaginary part of a complex number.",examples:["im(2 + 3i)","re(2 + 3i)","im(-5.2i)","im(2.4)"],seealso:["re","conj","abs","arg"]},er.docs.re={name:"re",category:"Complex",syntax:["re(x)"],description:"Get the real part of a complex number.",examples:["re(2 + 3i)","im(2 + 3i)","re(-5.2i)","re(2.4)"],seealso:["im","conj","abs","arg"]},er.docs["boolean"]={name:"boolean",category:"Type",syntax:["x","boolean(x)"],description:"Convert a string or number into a boolean.",examples:["boolean(0)","boolean(1)","boolean(3)",'boolean("true")','boolean("false")'],seealso:["complex","matrix","range","string","unit"]},er.docs.complex={name:"complex",category:"Type",syntax:["complex()","complex(re, im)","complex(string)"],description:"Create a complex number.",examples:["complex()","complex(2, 3)",'complex("7 - 2i")'],seealso:["boolean","matrix","number","range","string","unit"]},er.docs.matrix={name:"matrix",category:"Type",syntax:["[]","[a1, b1, ...; a2, b2, ...]","matrix()","matrix([...])"],description:"Create a matrix.",examples:["[]","[1, 2, 3]","[1, 2, 3; 4, 5, 6]","matrix()","matrix([3, 4])"],seealso:["boolean","complex","number","range","string","unit"]},er.docs.number={name:"number",category:"Type",syntax:["x","number(x)"],description:"Create a number or convert a string or boolean into a number.",examples:["2","2e3","4.05","number(2)",'number("7.2")',"number(true)"],seealso:["boolean","complex","matrix","range","string","unit"]},er.docs.range={name:"range",category:"Type",syntax:["start:end","start:step:end","range(start, end)","range(start, step, end)","range(string)"],description:"Create a range.",examples:["1:5","3:-1:-3","range(3, 6)","range(0, 2, 10)",'range("4:10")',"a = [1, 2, 3; 4, 5, 6]","a(:, 1:2)"],seealso:["boolean","complex","matrix","number","string","unit"]},er.docs.string={name:"string",category:"Type",syntax:['"text"',"string(x)"],description:"Create a string or convert a value to a string",examples:['"Hello World!"',"string(4.2)","string(3 + 2i)"],seealso:["boolean","complex","matrix","number","range","unit"]},er.docs.unit={name:"unit",category:"Type",syntax:["value unit","unit(value, unit)","unit(string)"],description:"Create a unit.",examples:["5.5 mm","3 inch",'unit(7.1, "kilogram")','unit("23 deg")'],seealso:["boolean","complex","matrix","number","range","string"]},er.docs.concat={name:"concat",category:"Matrix",syntax:["concat(a, b, c, ...)","concat(a, b, c, ..., dim)"],description:"Concatenate matrices. By default, the matrices are concatenated by the first dimension. The dimension on which to concatenate can be provided as last argument.",examples:["a = [1, 2; 5, 6]","b = [3, 4; 7, 8]","concat(a, b)","[a, b]","concat(a, b, 2)","[a; b]"],seealso:["det","diag","eye","inv","ones","size","squeeze","subset","transpose","zeros"]},er.docs.det={name:"det",category:"Matrix",syntax:["det(x)"],description:"Calculate the determinant of a matrix",examples:["det([1, 2; 3, 4])","det([-2, 2, 3; -1, 1, 3; 2, 0, -1])"],seealso:["concat","diag","eye","inv","ones","size","squeeze","subset","transpose","zeros"]},er.docs.diag={name:"diag",category:"Matrix",syntax:["diag(x)","diag(x, k)"],description:"Create a diagonal matrix or retrieve the diagonal of a matrix. When x is a vector, a matrix with the vector values on the diagonal will be returned. When x is a matrix, a vector with the diagonal values of the matrix is returned.When k is provided, the k-th diagonal will be filled in or retrieved, if k is positive, the values are placed on the super diagonal. When k is negative, the values are placed on the sub diagonal.",examples:["diag(1:4)","diag(1:4, 1)","a = [1, 2, 3; 4, 5, 6; 7, 8, 9]","diag(a)"],seealso:["concat","det","eye","inv","ones","size","squeeze","subset","transpose","zeros"]},er.docs.eye={name:"eye",category:"Matrix",syntax:["eye(n)","eye(m, n)","eye([m, n])","eye"],description:"Returns the identity matrix with size m-by-n. The matrix has ones on the diagonal and zeros elsewhere.",examples:["eye(3)","eye(3, 5)","a = [1, 2, 3; 4, 5, 6]","eye(size(a))"],seealso:["concat","det","diag","inv","ones","size","squeeze","subset","transpose","zeros"]},er.docs.inv={name:"inv",category:"Matrix",syntax:["inv(x)"],description:"Calculate the inverse of a matrix",examples:["inv([1, 2; 3, 4])","inv(4)","1 / 4"],seealso:["concat","det","diag","eye","ones","size","squeeze","subset","transpose","zeros"]},er.docs.ones={name:"ones",category:"Matrix",syntax:["ones(n)","ones(m, n)","ones(m, n, p, ...)","ones([m, n])","ones([m, n, p, ...])","ones"],description:"Create a matrix containing ones.",examples:["ones(3)","ones(3, 5)","ones([2,3]) * 4.5","a = [1, 2, 3; 4, 5, 6]","ones(size(a))"],seealso:["concat","det","diag","eye","inv","size","squeeze","subset","transpose","zeros"]},er.docs.size={name:"size",category:"Matrix",syntax:["size(x)"],description:"Calculate the size of a matrix.",examples:["size(2.3)",'size("hello world")',"a = [1, 2; 3, 4; 5, 6]","size(a)","size(1:6)"],seealso:["concat","det","diag","eye","inv","ones","squeeze","subset","transpose","zeros"]},er.docs.squeeze={name:"squeeze",category:"Matrix",syntax:["squeeze(x)"],description:"Remove singleton dimensions from a matrix.",examples:["a = zeros(1,3,2)","size(squeeze(a))","b = zeros(3,1,1)","size(squeeze(b))"],seealso:["concat","det","diag","eye","inv","ones","size","subset","transpose","zeros"]},er.docs.subset={name:"subset",category:"Matrix",syntax:["value(index)","value(index) = replacement","subset(value, [index])","subset(value, [index], replacement)"],description:"Get or set a subset of a matrix or string.",examples:["d = [1, 2; 3, 4]","e = []","e(0, 0:1) = [5, 6]","e(1, :) = [7, 8]","f = d * e","f(1, 0)","f(:, 0)"],seealso:["concat","det","diag","eye","inv","ones","range","size","squeeze","transpose","zeros"]},er.docs.transpose={name:"transpose",category:"Matrix",syntax:["x'","transpose(x)"],description:"Transpose a matrix",examples:["a = [1, 2, 3; 4, 5, 6]","a'","transpose(a)"],seealso:["concat","det","diag","eye","inv","ones","size","squeeze","subset","zeros"]},er.docs.zeros={name:"zeros",category:"Matrix",syntax:["zeros(n)","zeros(m, n)","zeros(m, n, p, ...)","zeros([m, n])","zeros([m, n, p, ...])","zeros"],description:"Create a matrix containing zeros.",examples:["zeros(3)","zeros(3, 5)","a = [1, 2, 3; 4, 5, 6]","zeros(size(a))"],seealso:["concat","det","diag","eye","inv","ones","size","squeeze","subset","transpose"]},er.docs.factorial={name:"factorial",category:"Probability",syntax:["x!","factorial(x)"],description:"Compute the factorial of a value",examples:["5!","5*4*3*2*1","3!"],seealso:[]},er.docs.random={name:"random",category:"Probability",syntax:["random(min, max)"],description:"Return a random number between 0 and 1.",examples:["random()"],seealso:[]},er.docs.randInt={name:"randInt",category:"Probability",syntax:["randInt()"],description:"Return a random number between 0 and 1.",examples:["randInt()"],seealso:[]},er.docs.max={name:"max",category:"Statistics",syntax:["max(a, b, c, ...)"],description:"Compute the maximum value of a list of values.",examples:["max(2, 3, 4, 1)","max(2.7, 7.1, -4.5, 2.0, 4.1)","min(2.7, 7.1, -4.5, 2.0, 4.1)"],seealso:["min"]},er.docs.min={name:"min",category:"Statistics",syntax:["min(a, b, c, ...)"],description:"Compute the minimum value of a list of values.",examples:["min(2, 3, 4, 1)","min(2.7, 7.1, -4.5, 2.0, 4.1)","max(2.7, 7.1, -4.5, 2.0, 4.1)"],seealso:["max"]},er.docs.acos={name:"acos",category:"Trigonometry",syntax:["acos(x)"],description:"Compute the inverse cosine of a value in radians.",examples:["acos(0.5)","acos(cos(2.3))"],seealso:["cos","acos","asin"]},er.docs.asin={name:"asin",category:"Trigonometry",syntax:["asin(x)"],description:"Compute the inverse sine of a value in radians.",examples:["asin(0.5)","asin(sin(2.3))"],seealso:["sin","acos","asin"]},er.docs.atan={name:"atan",category:"Trigonometry",syntax:["atan(x)"],description:"Compute the inverse tangent of a value in radians.",examples:["atan(0.5)","atan(tan(2.3))"],seealso:["tan","acos","asin"]},er.docs.atan2={name:"atan2",category:"Trigonometry",syntax:["atan2(y, x)"],description:"Computes the principal value of the arc tangent of y/x in radians.",examples:["atan2(2, 2) / pi","angle = 60 deg in rad","x = cos(angle)","y = sin(angle)","atan2(y, x)"],seealso:["sin","cos","tan"]},er.docs.cos={name:"cos",category:"Trigonometry",syntax:["cos(x)"],description:"Compute the cosine of x in radians.",examples:["cos(2)","cos(pi / 4) ^ 2","cos(180 deg)","cos(60 deg)","sin(0.2)^2 + cos(0.2)^2"],seealso:["acos","sin","tan"]},er.docs.cot={name:"cot",category:"Trigonometry",syntax:["cot(x)"],description:"Compute the cotangent of x in radians. Defined as 1/tan(x)",examples:["cot(2)","1 / tan(2)"],seealso:["sec","csc","tan"]},er.docs.csc={name:"csc",category:"Trigonometry",syntax:["csc(x)"],description:"Compute the cosecant of x in radians. Defined as 1/sin(x)",examples:["csc(2)","1 / sin(2)"],seealso:["sec","cot","sin"]},er.docs.sec={name:"sec",category:"Trigonometry",syntax:["sec(x)"],description:"Compute the secant of x in radians. Defined as 1/cos(x)",examples:["sec(2)","1 / cos(2)"],seealso:["cot","csc","cos"]},er.docs.sin={name:"sin",category:"Trigonometry",syntax:["sin(x)"],description:"Compute the sine of x in radians.",examples:["sin(2)","sin(pi / 4) ^ 2","sin(90 deg)","sin(30 deg)","sin(0.2)^2 + cos(0.2)^2"],seealso:["asin","cos","tan"]},er.docs.tan={name:"tan",category:"Trigonometry",syntax:["tan(x)"],description:"Compute the tangent of x in radians.",examples:["tan(0.5)","sin(0.5) / cos(0.5)","tan(pi / 4)","tan(45 deg)"],seealso:["atan","sin","cos"]},er.docs["in"]={name:"in",category:"Units",syntax:["x in unit","in(x, unit)"],description:"Change the unit of a value.",examples:["5 inch in cm","3.2kg in g","16 bytes in bits"],seealso:[]},er.docs.clone={name:"clone",category:"Utils",syntax:["clone(x)"],description:"Clone a variable. Creates a copy of primitive variables,and a deep copy of matrices",examples:["clone(3.5)","clone(2 - 4i)","clone(45 deg)","clone([1, 2; 3, 4])",'clone("hello world")'],seealso:[]},er.docs.eval={name:"eval",category:"Utils",syntax:["eval(expression)","eval([expr1, expr2, expr3, ...])"],description:"Evaluate an expression or an array with expressions.",examples:['eval("2 + 3")','eval("sqrt(" + 4 + ")")'],seealso:[]},er.docs.format={name:"format",category:"Utils",syntax:["format(value)"],description:"Format a value of any type as string.",examples:["format(2.3)","format(3 - 4i)","format([])"],seealso:[]},er.docs.help={name:"help",category:"Utils",syntax:["help(object)","help(string)"],description:"Display documentation on a function or data type.",examples:["help(sqrt)",'help("complex")'],seealso:[]},er.docs["import"]={name:"import",category:"Utils",syntax:["import(string)"],description:"Import functions from a file.",examples:['import("numbers")','import("./mylib.js")'],seealso:[]},er.docs["typeof"]={name:"typeof",category:"Utils",syntax:["typeof(x)"],description:"Get the type of a variable.",examples:["typeof(3.5)","typeof(2 - 4i)","typeof(45 deg)",'typeof("hello world")'],seealso:[]},Array.prototype.indexOf||(Array.prototype.indexOf=function(e){for(var r=0;rt;++t)e.call(r||this,this[t],t,this)}),Array.isArray||(Array.isArray=function(e){return"[object Array]"===Object.prototype.toString.call(e)}),Array.prototype.map||(Array.prototype.map=function(e,r){var t,n,a;if(null==this)throw new TypeError(" this is null or not defined");var i=Object(this),o=i.length>>>0;if("function"!=typeof e)throw new TypeError(e+" is not a function");for(r&&(t=r),n=new Array(o),a=0;o>a;){var s,u;a in i&&(s=i[a],u=e.call(t,s,a,i),n[a]=u),a++}return n}),Array.prototype.every||(Array.prototype.every=function(e){"use strict";if(null==this)throw new TypeError;var r=Object(this),t=r.length>>>0;if("function"!=typeof e)throw new TypeError;for(var n=arguments[1],a=0;t>a;a++)if(a in r&&!e.call(n,r[a],a,r))return!1;return!0}),Array.prototype.some||(Array.prototype.some=function(e){"use strict";if(null==this)throw new TypeError;var r=Object(this),t=r.length>>>0;if("function"!=typeof e)throw new TypeError;for(var n=arguments[1],a=0;t>a;a++)if(a in r&&e.call(n,r[a],a,r))return!0;return!1}),Function.prototype.bind||(Function.prototype.bind=function(e){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var r=Array.prototype.slice.call(arguments,1),t=this,n=function(){},a=function(){return t.apply(this instanceof n&&e?this:e,r.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,a.prototype=new n,a});for(var or in er)er.hasOwnProperty(or)&&or&&y(or,er[or]);"undefined"!=typeof module&&"undefined"!=typeof module.exports&&(module.exports=er),"undefined"!=typeof exports&&(exports=er),"undefined"!=typeof require&&"undefined"!=typeof define&&define(function(){return er}),"undefined"!=typeof window&&(window.math?rr.deepExtend(window.math,er):window.math=er)}(); \ No newline at end of file +!function(e){if("function"==typeof bootstrap)bootstrap("math",e);else if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else if("undefined"!=typeof ses){if(!ses.ok())return;ses.makeMath=e}else"undefined"!=typeof window?window.math=e():global.math=e()}(function(){return function e(t,n,r){function i(a,s){if(!n[a]){if(!t[a]){var u="function"==typeof require&&require;if(!s&&u)return u(a,!0);if(o)return o(a,!0);throw new Error("Cannot find module '"+a+"'")}var c=n[a]={exports:{}};t[a][0].call(c.exports,function(e){var n=t[a][1][e];return i(n?n:e)},c,c.exports,e,t,n,r)}return n[a].exports}for(var o="function"==typeof require&&require,a=0;a y","larger(x, y)"],description:"Check if value x is larger than y. Returns 1 if x is larger than y, and 0 if not.",examples:["2 > 3","5 > 2*2","a = 3.3","b = 6-2.8","(a > b)","(b < a)","5 cm > 2 inch"],seealso:["equal","unequal","smaller","smallereq","largereq"]}},{}],30:[function(e,t){t.exports={name:"largereq",category:"Operators",syntax:["x >= y","largereq(x, y)"],description:"Check if value x is larger or equal to y. Returns 1 if x is larger or equal to y, and 0 if not.",examples:["2 > 1+1","2 >= 1+1","a = 3.2","b = 6-2.8","(a > b)"],seealso:["equal","unequal","smallereq","smaller","largereq"]}},{}],31:[function(e,t){t.exports={name:"lcm",category:"Arithmetic",syntax:["lcm(x, y)"],description:"Compute the least common multiple.",examples:["lcm(4, 6)","lcm(6, 21)","lcm(6, 21, 5)"],seealso:["gcd"]}},{}],32:[function(e,t){t.exports={name:"log",category:"Arithmetic",syntax:["log(x)","log(x, base)"],description:"Compute the logarithm of a value. If no base is provided, the natural logarithm of x is calculated. If base if provided, the logarithm is calculated for the specified base. log(x, base) is defined as log(x) / log(base).",examples:["log(3.5)","a = log(2.4)","exp(a)","10 ^ 3","log(1000, 10)","log(1000) / log(10)","b = logb(1024, 2)","2 ^ b"],seealso:["exp","log10"]}},{}],33:[function(e,t){t.exports={name:"log10",category:"Arithmetic",syntax:["log10(x)"],description:"Compute the 10-base logarithm of a value.",examples:["log10(1000)","10 ^ 3","log10(0.01)","log(1000) / log(10)","log(1000, 10)"],seealso:["exp","log"]}},{}],34:[function(e,t){t.exports={name:"mod",category:"Operators",syntax:["x % y","x mod y","mod(x, y)"],description:"Calculates the modulus, the remainder of an integer division.",examples:["7 % 3","11 % 2","10 mod 4","function isOdd(x) = x % 2","isOdd(2)","isOdd(3)"],seealso:[]}},{}],35:[function(e,t){t.exports={name:"multiply",category:"Operators",syntax:["x * y","multiply(x, y)"],description:"multiply two values.",examples:["2.1 * 3.6","ans / 3.6","2 * 3 + 4","2 * (3 + 4)","3 * 2.1 km"],seealso:["divide"]}},{}],36:[function(e,t){t.exports={name:"pow",category:"Operators",syntax:["x ^ y","pow(x, y)"],description:"Calculates the power of x to y, x^y.",examples:["2^3 = 8","2*2*2","1 + e ^ (pi * i)"],seealso:["unequal","smaller","larger","smallereq","largereq"]}},{}],37:[function(e,t){t.exports={name:"round",category:"Arithmetic",syntax:["round(x)","round(x, n)"],description:"round a value towards the nearest integer.If x is complex, both real and imaginary part are rounded towards the nearest integer. When n is specified, the value is rounded to n decimals.",examples:["round(3.2)","round(3.8)","round(-4.2)","round(-4.8)","round(pi, 3)","round(123.45678, 2)"],seealso:["ceil","floor","fix"]}},{}],38:[function(e,t){t.exports={name:"sign",category:"Arithmetic",syntax:["sign(x)"],description:"Compute the sign of a value. The sign of a value x is 1 when x>1, -1 when x<0, and 0 when x=0.",examples:["sign(3.5)","sign(-4.2)","sign(0)"],seealso:["abs"]}},{}],39:[function(e,t){t.exports={name:"smaller",category:"Operators",syntax:["x < y","smaller(x, y)"],description:"Check if value x is smaller than value y. Returns 1 if x is smaller than y, and 0 if not.",examples:["2 < 3","5 < 2*2","a = 3.3","b = 6-2.8","(a < b)","5 cm < 2 inch"],seealso:["equal","unequal","larger","smallereq","largereq"]}},{}],40:[function(e,t){t.exports={name:"smallereq",category:"Operators",syntax:["x <= y","smallereq(x, y)"],description:"Check if value x is smaller or equal to value y. Returns 1 if x is smaller than y, and 0 if not.",examples:["2 < 1+1","2 <= 1+1","a = 3.2","b = 6-2.8","(a < b)"],seealso:["equal","unequal","larger","smaller","largereq"]}},{}],41:[function(e,t){t.exports={name:"sqrt",category:"Arithmetic",syntax:["sqrt(x)"],description:"Compute the square root value. If x = y * y, then y is the square root of x.",examples:["sqrt(25)","5 * 5","sqrt(-1)"],seealso:["square","multiply"]}},{}],42:[function(e,t){t.exports={name:"square",category:"Arithmetic",syntax:["square(x)"],description:"Compute the square of a value. The square of x is x * x.",examples:["square(3)","sqrt(9)","3^2","3 * 3"],seealso:["multiply","pow","sqrt","cube"]}},{}],43:[function(e,t){t.exports={name:"subtract",category:"Operators",syntax:["x - y","subtract(x, y)"],description:"subtract two values.",examples:["5.3 - 2","ans + 2","2/3 - 1/6","2 * 3 - 3","2.1 km - 500m"],seealso:["add"]}},{}],44:[function(e,t){t.exports={name:"unary",category:"Operators",syntax:["-x","unary(x)"],description:"Inverse the sign of a value.",examples:["-4.5","-(-5.6)"],seealso:["add","subtract"]}},{}],45:[function(e,t){t.exports={name:"unequal",category:"Operators",syntax:["x != y","unequal(x, y)"],description:"Check unequality of two values. Returns 1 if the values are unequal, and 0 if they are equal.",examples:["2+2 != 3","2+2 != 4","a = 3.2","b = 6-2.8","a != b","50cm != 0.5m","5 cm != 2 inch"],seealso:["equal","smaller","larger","smallereq","largereq"]}},{}],46:[function(e,t){t.exports={name:"xgcd",category:"Arithmetic",syntax:["xgcd(a, b)"],description:"Calculate the extended greatest common divisor for two values",examples:["xgcd(8, 12)","gcd(8, 12)","xgcd(36163, 21199)"],seealso:["gcd","lcm"]}},{}],47:[function(e,t){t.exports={name:"arg",category:"Complex",syntax:["arg(x)"],description:"Compute the argument of a complex value. If x = a+bi, the argument is computed as atan2(b, a).",examples:["arg(2 + 2i)","atan2(3, 2)","arg(2 - 3i)"],seealso:["re","im","conj","abs"]}},{}],48:[function(e,t){t.exports={name:"conj",category:"Complex",syntax:["conj(x)"],description:"Compute the complex conjugate of a complex value. If x = a+bi, the complex conjugate is a-bi.",examples:["conj(2 + 3i)","conj(2 - 3i)","conj(-5.2i)"],seealso:["re","im","abs","arg"]}},{}],49:[function(e,t){t.exports={name:"im",category:"Complex",syntax:["im(x)"],description:"Get the imaginary part of a complex number.",examples:["im(2 + 3i)","re(2 + 3i)","im(-5.2i)","im(2.4)"],seealso:["re","conj","abs","arg"]}},{}],50:[function(e,t){t.exports={name:"re",category:"Complex",syntax:["re(x)"],description:"Get the real part of a complex number.",examples:["re(2 + 3i)","im(2 + 3i)","re(-5.2i)","re(2.4)"],seealso:["im","conj","abs","arg"]}},{}],51:[function(e,t){t.exports={name:"boolean",category:"Type",syntax:["x","boolean(x)"],description:"Convert a string or number into a boolean.",examples:["boolean(0)","boolean(1)","boolean(3)",'boolean("true")','boolean("false")'],seealso:["complex","matrix","range","string","unit"]}},{}],52:[function(e,t){t.exports={name:"complex",category:"Type",syntax:["complex()","complex(re, im)","complex(string)"],description:"Create a complex number.",examples:["complex()","complex(2, 3)",'complex("7 - 2i")'],seealso:["boolean","matrix","number","range","string","unit"]}},{}],53:[function(e,t){t.exports={name:"matrix",category:"Type",syntax:["[]","[a1, b1, ...; a2, b2, ...]","matrix()","matrix([...])"],description:"Create a matrix.",examples:["[]","[1, 2, 3]","[1, 2, 3; 4, 5, 6]","matrix()","matrix([3, 4])"],seealso:["boolean","complex","number","range","string","unit"]}},{}],54:[function(e,t){t.exports={name:"number",category:"Type",syntax:["x","number(x)"],description:"Create a number or convert a string or boolean into a number.",examples:["2","2e3","4.05","number(2)",'number("7.2")',"number(true)"],seealso:["boolean","complex","matrix","range","string","unit"]}},{}],55:[function(e,t){t.exports={name:"range",category:"Type",syntax:["start:end","start:step:end","range(start, end)","range(start, step, end)","range(string)"],description:"Create a range.",examples:["1:5","3:-1:-3","range(3, 6)","range(0, 2, 10)",'range("4:10")',"a = [1, 2, 3; 4, 5, 6]","a(:, 1:2)"],seealso:["boolean","complex","matrix","number","string","unit"]}},{}],56:[function(e,t){t.exports={name:"string",category:"Type",syntax:['"text"',"string(x)"],description:"Create a string or convert a value to a string",examples:['"Hello World!"',"string(4.2)","string(3 + 2i)"],seealso:["boolean","complex","matrix","number","range","unit"]}},{}],57:[function(e,t){t.exports={name:"unit",category:"Type",syntax:["value unit","unit(value, unit)","unit(string)"],description:"Create a unit.",examples:["5.5 mm","3 inch",'unit(7.1, "kilogram")','unit("23 deg")'],seealso:["boolean","complex","matrix","number","range","string"]}},{}],58:[function(e,t){t.exports={name:"concat",category:"Matrix",syntax:["concat(a, b, c, ...)","concat(a, b, c, ..., dim)"],description:"Concatenate matrices. By default, the matrices are concatenated by the first dimension. The dimension on which to concatenate can be provided as last argument.",examples:["a = [1, 2; 5, 6]","b = [3, 4; 7, 8]","concat(a, b)","[a, b]","concat(a, b, 2)","[a; b]"],seealso:["det","diag","eye","inv","ones","size","squeeze","subset","transpose","zeros"]}},{}],59:[function(e,t){t.exports={name:"det",category:"Matrix",syntax:["det(x)"],description:"Calculate the determinant of a matrix",examples:["det([1, 2; 3, 4])","det([-2, 2, 3; -1, 1, 3; 2, 0, -1])"],seealso:["concat","diag","eye","inv","ones","size","squeeze","subset","transpose","zeros"]}},{}],60:[function(e,t){t.exports={name:"diag",category:"Matrix",syntax:["diag(x)","diag(x, k)"],description:"Create a diagonal matrix or retrieve the diagonal of a matrix. When x is a vector, a matrix with the vector values on the diagonal will be returned. When x is a matrix, a vector with the diagonal values of the matrix is returned.When k is provided, the k-th diagonal will be filled in or retrieved, if k is positive, the values are placed on the super diagonal. When k is negative, the values are placed on the sub diagonal.",examples:["diag(1:4)","diag(1:4, 1)","a = [1, 2, 3; 4, 5, 6; 7, 8, 9]","diag(a)"],seealso:["concat","det","eye","inv","ones","size","squeeze","subset","transpose","zeros"]}},{}],61:[function(e,t){t.exports={name:"eye",category:"Matrix",syntax:["eye(n)","eye(m, n)","eye([m, n])","eye"],description:"Returns the identity matrix with size m-by-n. The matrix has ones on the diagonal and zeros elsewhere.",examples:["eye(3)","eye(3, 5)","a = [1, 2, 3; 4, 5, 6]","eye(size(a))"],seealso:["concat","det","diag","inv","ones","size","squeeze","subset","transpose","zeros"]}},{}],62:[function(e,t){t.exports={name:"inv",category:"Matrix",syntax:["inv(x)"],description:"Calculate the inverse of a matrix",examples:["inv([1, 2; 3, 4])","inv(4)","1 / 4"],seealso:["concat","det","diag","eye","ones","size","squeeze","subset","transpose","zeros"]}},{}],63:[function(e,t){t.exports={name:"ones",category:"Matrix",syntax:["ones(n)","ones(m, n)","ones(m, n, p, ...)","ones([m, n])","ones([m, n, p, ...])","ones"],description:"Create a matrix containing ones.",examples:["ones(3)","ones(3, 5)","ones([2,3]) * 4.5","a = [1, 2, 3; 4, 5, 6]","ones(size(a))"],seealso:["concat","det","diag","eye","inv","size","squeeze","subset","transpose","zeros"]}},{}],64:[function(e,t){t.exports={name:"size",category:"Matrix",syntax:["size(x)"],description:"Calculate the size of a matrix.",examples:["size(2.3)",'size("hello world")',"a = [1, 2; 3, 4; 5, 6]","size(a)","size(1:6)"],seealso:["concat","det","diag","eye","inv","ones","squeeze","subset","transpose","zeros"]}},{}],65:[function(e,t){t.exports={name:"squeeze",category:"Matrix",syntax:["squeeze(x)"],description:"Remove singleton dimensions from a matrix.",examples:["a = zeros(1,3,2)","size(squeeze(a))","b = zeros(3,1,1)","size(squeeze(b))"],seealso:["concat","det","diag","eye","inv","ones","size","subset","transpose","zeros"]}},{}],66:[function(e,t){t.exports={name:"subset",category:"Matrix",syntax:["value(index)","value(index) = replacement","subset(value, [index])","subset(value, [index], replacement)"],description:"Get or set a subset of a matrix or string.",examples:["d = [1, 2; 3, 4]","e = []","e(0, 0:1) = [5, 6]","e(1, :) = [7, 8]","f = d * e","f(1, 0)","f(:, 0)"],seealso:["concat","det","diag","eye","inv","ones","range","size","squeeze","transpose","zeros"]}},{}],67:[function(e,t){t.exports={name:"transpose",category:"Matrix",syntax:["x'","transpose(x)"],description:"Transpose a matrix",examples:["a = [1, 2, 3; 4, 5, 6]","a'","transpose(a)"],seealso:["concat","det","diag","eye","inv","ones","size","squeeze","subset","zeros"]}},{}],68:[function(e,t){t.exports={name:"zeros",category:"Matrix",syntax:["zeros(n)","zeros(m, n)","zeros(m, n, p, ...)","zeros([m, n])","zeros([m, n, p, ...])","zeros"],description:"Create a matrix containing zeros.",examples:["zeros(3)","zeros(3, 5)","a = [1, 2, 3; 4, 5, 6]","zeros(size(a))"],seealso:["concat","det","diag","eye","inv","ones","size","squeeze","subset","transpose"]}},{}],69:[function(e,t){t.exports={name:"factorial",category:"Probability",syntax:["x!","factorial(x)"],description:"Compute the factorial of a value",examples:["5!","5*4*3*2*1","3!"],seealso:[]}},{}],70:[function(e,t){t.exports={name:"random",category:"Probability",syntax:["random(min, max)"],description:"Return a random number between 0 and 1.",examples:["random()"],seealso:[]}},{}],71:[function(e,t){t.exports={name:"randInt",category:"Probability",syntax:["randInt()"],description:"Return a random number between 0 and 1.",examples:["randInt()"],seealso:[]}},{}],72:[function(e,t){t.exports={name:"max",category:"Statistics",syntax:["max(a, b, c, ...)"],description:"Compute the maximum value of a list of values.",examples:["max(2, 3, 4, 1)","max(2.7, 7.1, -4.5, 2.0, 4.1)","min(2.7, 7.1, -4.5, 2.0, 4.1)"],seealso:["min"]}},{}],73:[function(e,t){t.exports={name:"min",category:"Statistics",syntax:["min(a, b, c, ...)"],description:"Compute the minimum value of a list of values.",examples:["min(2, 3, 4, 1)","min(2.7, 7.1, -4.5, 2.0, 4.1)","max(2.7, 7.1, -4.5, 2.0, 4.1)"],seealso:["max"]}},{}],74:[function(e,t){t.exports={name:"acos",category:"Trigonometry",syntax:["acos(x)"],description:"Compute the inverse cosine of a value in radians.",examples:["acos(0.5)","acos(cos(2.3))"],seealso:["cos","acos","asin"]}},{}],75:[function(e,t){t.exports={name:"asin",category:"Trigonometry",syntax:["asin(x)"],description:"Compute the inverse sine of a value in radians.",examples:["asin(0.5)","asin(sin(2.3))"],seealso:["sin","acos","asin"]}},{}],76:[function(e,t){t.exports={name:"atan",category:"Trigonometry",syntax:["atan(x)"],description:"Compute the inverse tangent of a value in radians.",examples:["atan(0.5)","atan(tan(2.3))"],seealso:["tan","acos","asin"]}},{}],77:[function(e,t){t.exports={name:"atan2",category:"Trigonometry",syntax:["atan2(y, x)"],description:"Computes the principal value of the arc tangent of y/x in radians.",examples:["atan2(2, 2) / pi","angle = 60 deg in rad","x = cos(angle)","y = sin(angle)","atan2(y, x)"],seealso:["sin","cos","tan"]}},{}],78:[function(e,t){t.exports={name:"cos",category:"Trigonometry",syntax:["cos(x)"],description:"Compute the cosine of x in radians.",examples:["cos(2)","cos(pi / 4) ^ 2","cos(180 deg)","cos(60 deg)","sin(0.2)^2 + cos(0.2)^2"],seealso:["acos","sin","tan"]}},{}],79:[function(e,t){t.exports={name:"cot",category:"Trigonometry",syntax:["cot(x)"],description:"Compute the cotangent of x in radians. Defined as 1/tan(x)",examples:["cot(2)","1 / tan(2)"],seealso:["sec","csc","tan"]}},{}],80:[function(e,t){t.exports={name:"csc",category:"Trigonometry",syntax:["csc(x)"],description:"Compute the cosecant of x in radians. Defined as 1/sin(x)",examples:["csc(2)","1 / sin(2)"],seealso:["sec","cot","sin"]}},{}],81:[function(e,t){t.exports={name:"sec",category:"Trigonometry",syntax:["sec(x)"],description:"Compute the secant of x in radians. Defined as 1/cos(x)",examples:["sec(2)","1 / cos(2)"],seealso:["cot","csc","cos"]}},{}],82:[function(e,t){t.exports={name:"sin",category:"Trigonometry",syntax:["sin(x)"],description:"Compute the sine of x in radians.",examples:["sin(2)","sin(pi / 4) ^ 2","sin(90 deg)","sin(30 deg)","sin(0.2)^2 + cos(0.2)^2"],seealso:["asin","cos","tan"]}},{}],83:[function(e,t){t.exports={name:"tan",category:"Trigonometry",syntax:["tan(x)"],description:"Compute the tangent of x in radians.",examples:["tan(0.5)","sin(0.5) / cos(0.5)","tan(pi / 4)","tan(45 deg)"],seealso:["atan","sin","cos"]}},{}],84:[function(e,t){t.exports={name:"in",category:"Units",syntax:["x in unit","in(x, unit)"],description:"Change the unit of a value.",examples:["5 inch in cm","3.2kg in g","16 bytes in bits"],seealso:[]}},{}],85:[function(e,t){t.exports={name:"clone",category:"Utils",syntax:["clone(x)"],description:"Clone a variable. Creates a copy of primitive variables,and a deep copy of matrices",examples:["clone(3.5)","clone(2 - 4i)","clone(45 deg)","clone([1, 2; 3, 4])",'clone("hello world")'],seealso:[]}},{}],86:[function(e,t){t.exports={name:"eval",category:"Utils",syntax:["eval(expression)","eval([expr1, expr2, expr3, ...])"],description:"Evaluate an expression or an array with expressions.",examples:['eval("2 + 3")','eval("sqrt(" + 4 + ")")'],seealso:[]}},{}],87:[function(e,t){t.exports={name:"format",category:"Utils",syntax:["format(value)"],description:"Format a value of any type as string.",examples:["format(2.3)","format(3 - 4i)","format([])"],seealso:[]}},{}],88:[function(e,t){t.exports={name:"help",category:"Utils",syntax:["help(object)","help(string)"],description:"Display documentation on a function or data type.",examples:["help(sqrt)",'help("complex")'],seealso:[]}},{}],89:[function(e,t){t.exports={name:"import",category:"Utils",syntax:["import(string)"],description:"Import functions from a file.",examples:['import("numbers")','import("./mylib.js")'],seealso:[]}},{}],90:[function(e,t){t.exports={name:"typeof",category:"Utils",syntax:["typeof(x)"],description:"Get the type of a variable.",examples:["typeof(3.5)","typeof(2 - 4i)","typeof(45 deg)",'typeof("hello world")'],seealso:[]}},{}],91:[function(e,t,n){n.e=e("./constants/e.js"),n.E=e("./constants/e.js"),n["false"]=e("./constants/false.js"),n.i=e("./constants/i.js"),n.Infinity=e("./constants/Infinity.js"),n.LN2=e("./constants/LN2.js"),n.LN10=e("./constants/LN10.js"),n.LOG2E=e("./constants/LOG2E.js"),n.LOG10E=e("./constants/LOG10E.js"),n.NaN=e("./constants/NaN.js"),n.pi=e("./constants/pi.js"),n.PI=e("./constants/pi.js"),n.SQRT1_2=e("./constants/SQRT1_2.js"),n.SQRT2=e("./constants/SQRT2.js"),n.tau=e("./constants/tau.js"),n["true"]=e("./constants/true.js"),n.abs=e("./function/arithmetic/abs.js"),n.add=e("./function/arithmetic/add.js"),n.ceil=e("./function/arithmetic/ceil.js"),n.cube=e("./function/arithmetic/cube.js"),n.divide=e("./function/arithmetic/divide.js"),n.edivide=e("./function/arithmetic/edivide.js"),n.emultiply=e("./function/arithmetic/emultiply.js"),n.epow=e("./function/arithmetic/epow.js"),n.equal=e("./function/arithmetic/equal.js"),n.exp=e("./function/arithmetic/exp.js"),n.fix=e("./function/arithmetic/fix.js"),n.floor=e("./function/arithmetic/floor.js"),n.gcd=e("./function/arithmetic/gcd.js"),n.larger=e("./function/arithmetic/larger.js"),n.largereq=e("./function/arithmetic/largereq.js"),n.lcm=e("./function/arithmetic/lcm.js"),n.log=e("./function/arithmetic/log.js"),n.log10=e("./function/arithmetic/log10.js"),n.mod=e("./function/arithmetic/mod.js"),n.multiply=e("./function/arithmetic/multiply.js"),n.pow=e("./function/arithmetic/pow.js"),n.round=e("./function/arithmetic/round.js"),n.sign=e("./function/arithmetic/sign.js"),n.smaller=e("./function/arithmetic/smaller.js"),n.smallereq=e("./function/arithmetic/smallereq.js"),n.sqrt=e("./function/arithmetic/sqrt.js"),n.square=e("./function/arithmetic/square.js"),n.subtract=e("./function/arithmetic/subtract.js"),n.unary=e("./function/arithmetic/unary.js"),n.unequal=e("./function/arithmetic/unequal.js"),n.xgcd=e("./function/arithmetic/xgcd.js"),n.arg=e("./function/complex/arg.js"),n.conj=e("./function/complex/conj.js"),n.re=e("./function/complex/re.js"),n.im=e("./function/complex/im.js"),n.boolean=e("./function/construction/boolean.js"),n.complex=e("./function/construction/complex.js"),n.matrix=e("./function/construction/matrix.js"),n.number=e("./function/construction/number.js"),n.range=e("./function/construction/range.js"),n.string=e("./function/construction/string.js"),n.unit=e("./function/construction/unit.js"),n.concat=e("./function/matrix/concat.js"),n.det=e("./function/matrix/det.js"),n.diag=e("./function/matrix/diag.js"),n.eye=e("./function/matrix/eye.js"),n.inv=e("./function/matrix/inv.js"),n.ones=e("./function/matrix/ones.js"),n.size=e("./function/matrix/size.js"),n.squeeze=e("./function/matrix/squeeze.js"),n.subset=e("./function/matrix/subset.js"),n.transpose=e("./function/matrix/transpose.js"),n.zeros=e("./function/matrix/zeros.js"),n.factorial=e("./function/probability/factorial.js"),n.random=e("./function/probability/random.js"),n.randomInt=e("./function/probability/randomInt.js"),n.min=e("./function/statistics/min.js"),n.max=e("./function/statistics/max.js"),n.acos=e("./function/trigonometry/acos.js"),n.asin=e("./function/trigonometry/asin.js"),n.atan=e("./function/trigonometry/atan.js"),n.atan2=e("./function/trigonometry/atan2.js"),n.cos=e("./function/trigonometry/cos.js"),n.cot=e("./function/trigonometry/cot.js"),n.csc=e("./function/trigonometry/csc.js"),n.sec=e("./function/trigonometry/sec.js"),n.sin=e("./function/trigonometry/sin.js"),n.tan=e("./function/trigonometry/tan.js"),n["in"]=e("./function/units/in.js"),n.clone=e("./function/utils/clone.js"),n.eval=e("./function/utils/eval.js"),n.format=e("./function/utils/format.js"),n.help=e("./function/utils/help.js"),n["import"]=e("./function/utils/import.js"),n["typeof"]=e("./function/utils/typeof.js")},{"./constants/Infinity.js":2,"./constants/LN10.js":3,"./constants/LN2.js":4,"./constants/LOG10E.js":5,"./constants/LOG2E.js":6,"./constants/NaN.js":7,"./constants/SQRT1_2.js":8,"./constants/SQRT2.js":9,"./constants/e.js":10,"./constants/false.js":11,"./constants/i.js":12,"./constants/pi.js":13,"./constants/tau.js":14,"./constants/true.js":15,"./function/arithmetic/abs.js":16,"./function/arithmetic/add.js":17,"./function/arithmetic/ceil.js":18,"./function/arithmetic/cube.js":19,"./function/arithmetic/divide.js":20,"./function/arithmetic/edivide.js":21,"./function/arithmetic/emultiply.js":22,"./function/arithmetic/epow.js":23,"./function/arithmetic/equal.js":24,"./function/arithmetic/exp.js":25,"./function/arithmetic/fix.js":26,"./function/arithmetic/floor.js":27,"./function/arithmetic/gcd.js":28,"./function/arithmetic/larger.js":29,"./function/arithmetic/largereq.js":30,"./function/arithmetic/lcm.js":31,"./function/arithmetic/log.js":32,"./function/arithmetic/log10.js":33,"./function/arithmetic/mod.js":34,"./function/arithmetic/multiply.js":35,"./function/arithmetic/pow.js":36,"./function/arithmetic/round.js":37,"./function/arithmetic/sign.js":38,"./function/arithmetic/smaller.js":39,"./function/arithmetic/smallereq.js":40,"./function/arithmetic/sqrt.js":41,"./function/arithmetic/square.js":42,"./function/arithmetic/subtract.js":43,"./function/arithmetic/unary.js":44,"./function/arithmetic/unequal.js":45,"./function/arithmetic/xgcd.js":46,"./function/complex/arg.js":47,"./function/complex/conj.js":48,"./function/complex/im.js":49,"./function/complex/re.js":50,"./function/construction/boolean.js":51,"./function/construction/complex.js":52,"./function/construction/matrix.js":53,"./function/construction/number.js":54,"./function/construction/range.js":55,"./function/construction/string.js":56,"./function/construction/unit.js":57,"./function/matrix/concat.js":58,"./function/matrix/det.js":59,"./function/matrix/diag.js":60,"./function/matrix/eye.js":61,"./function/matrix/inv.js":62,"./function/matrix/ones.js":63,"./function/matrix/size.js":64,"./function/matrix/squeeze.js":65,"./function/matrix/subset.js":66,"./function/matrix/transpose.js":67,"./function/matrix/zeros.js":68,"./function/probability/factorial.js":69,"./function/probability/random.js":70,"./function/probability/randomInt.js":71,"./function/statistics/max.js":72,"./function/statistics/min.js":73,"./function/trigonometry/acos.js":74,"./function/trigonometry/asin.js":75,"./function/trigonometry/atan.js":76,"./function/trigonometry/atan2.js":77,"./function/trigonometry/cos.js":78,"./function/trigonometry/cot.js":79,"./function/trigonometry/csc.js":80,"./function/trigonometry/sec.js":81,"./function/trigonometry/sin.js":82,"./function/trigonometry/tan.js":83,"./function/units/in.js":84,"./function/utils/clone.js":85,"./function/utils/eval.js":86,"./function/utils/format.js":87,"./function/utils/help.js":88,"./function/utils/import.js":89,"./function/utils/typeof.js":90}],92:[function(e,t){function n(){if(!(this instanceof n))throw new SyntaxError("Parser constructor must be called with the new operator"); +this.scope=new i}var r=e("../math.js"),i=e("./Scope.js");n.prototype.parse=function(e){return r.parse(e,this.scope)},n.prototype.eval=function(e){var t=r.parse(e,this.scope);return t.eval()},n.prototype.get=function(e){return this.scope.get(e)},n.prototype.set=function(e,t){this.scope.set(e,t)},n.prototype.remove=function(e){this.scope.remove(e)},n.prototype.clear=function(){this.scope.clear()},t.exports=n},{"../math.js":186,"./Scope.js":93}],93:[function(e,t){function n(){if(this.parentScope=null,this.subScopes=null,this.symbols={},this.cache={},arguments.length>0){var e=arguments[0];e instanceof n?this.parentScope=e:e instanceof Object&&(this.symbols=e)}if(arguments.length>1){var t=arguments[1];t instanceof Object&&(this.symbols=t)}}var r=e("../math.js"),i=e("../type/Unit.js");n.prototype={createSubScope:function(){var e=new n(this);return this.subScopes||(this.subScopes=[]),this.subScopes.push(e),e},get:function(e){var t;if(t=this.symbols[e],void 0!==t)return t;var n=this.cache[e];if(n)return n[e];for(var o=this.parentScope;o;){if(t=o.symbols[e],void 0!==t)return this.cache[e]=o.symbols,t;o=o.parentScope}return t=r[e],void 0!==t?(this.cache[e]=r,t):i.isPlainUnit(e)?(t=new i(null,e),this.cache[e]={},this.cache[e][e]=t,t):void 0},has:function(e){return void 0!==this.symbols[e]},set:function(e,t){return this.symbols[e]=t},remove:function(e){delete this.symbols[e]},clear:function(){var e=this.symbols;for(var t in e)e.hasOwnProperty(t)&&delete e[t];if(this.subScopes)for(var n=this.subScopes,r=0,i=n.length;i>r;r++)n[r].clear();this.clearCache()},clearCache:function(){this.cache={}}},t.exports=n},{"../math.js":186,"../type/Unit.js":192}],94:[function(e,t){t.exports=function(n){function r(e){if(!(this instanceof r))throw new SyntaxError("Selector constructor must be called with the new operator");this.value=e instanceof r?e.value:e}function i(e,t){var n=Array.prototype.slice;r.prototype[e]="function"==typeof t?function(){var e=[this.value].concat(n.call(arguments,0));return new r(t.apply(this,e))}:new r(t)}function o(){o=null;for(var e in n)n.hasOwnProperty(e)&&e&&i(e,n[e])}var a=e("../util/index.js"),s=a.string;r.prototype={done:function(){return this.value},get:function(e){var t=this.value;if(!t)throw Error("Selector value is undefined");return new r(n.subset(t,e))},set:function(e,t){var i=this.value;if(!i)throw Error("Selector value is undefined");return new r(n.subset(i,e,t))},valueOf:function(){return this.value},toString:function(){return s.format(this.value)}},r.createProxy=i,t.exports=r,r.init=o,a.types.addType("selector",r)}},{"../util/index.js":198}],95:[function(e,t,n){n.node=e("./node/index.js"),n.Scope=e("./Scope.js"),n.Parser=e("./Parser.js"),n.Selector=e("./Selector.js")},{"./Parser.js":92,"./Scope.js":93,"./Selector.js":94,"./node/index.js":107}],96:[function(e,t){function n(e,t,n){this.name=e,this.expr=t,this.scope=n}var r=e("./Node.js");n.prototype=new r,n.prototype.eval=function(){if(void 0===this.expr)throw new Error("Undefined symbol "+this.name);var e=this.expr.eval();return this.scope.set(this.name,e),e},n.prototype.find=function(e){var t=[];return this.match(e)&&t.push(this),this.expr&&(t=t.concat(this.expr.find(e))),t},n.prototype.toString=function(){return this.name+" = "+this.expr.toString()},t.exports=n},{"./Node.js":101}],97:[function(e,t){function n(){this.params=[],this.visible=[]}var r=e("./Node.js");n.prototype=new r,n.prototype.add=function(e,t){var n=this.params.length;this.params[n]=e,this.visible[n]=void 0!=t?t:!0},n.prototype.eval=function(){for(var e=[],t=0,n=this.params.length;n>t;t++){var r=this.params[t].eval();this.visible[t]&&e.push(r)}return e},n.prototype.find=function(e){var t=[];this.match(e)&&t.push(this);var n=this.params;if(n)for(var r=0,i=n.length;i>r;r++)t=t.concat(n[r].find(e));return t},n.prototype.toString=function(){for(var e=[],t=0,n=this.params.length;n>t;t++)this.visible[t]&&e.push("\n "+this.params[t].toString());return"["+e.join(",")+"\n]"},t.exports=n},{"./Node.js":101}],98:[function(e,t){function n(e){this.value=e}var r=e("./Node.js"),i=e("../../util/string.js");n.prototype=new r,n.prototype.eval=function(){return this.value},n.prototype.toString=function(){return i.format(this.value)},t.exports=n},{"../../util/string.js":201,"./Node.js":101}],99:[function(e,t){function n(e,t,n,r,o){this.name=e,this.variables=t,this.expr=n,this.scope=o,this.fn=function(){var o=t?t.length:0;if(arguments.length!=o)throw new i.ArgumentsError(e,arguments.length,o);for(var a=0;o>a;a++)r.set(t[a],arguments[a]);return n.eval()},this.fn.toString=function(){return e+"("+t.join(", ")+")"}}var r=e("./Node.js"),i=e("../../util/error.js");n.prototype=new r,n.prototype.eval=function(){return this.scope.set(this.name,this.fn),this.fn},n.prototype.find=function(e){var t=[];return this.match(e)&&t.push(this),this.expr&&(t=t.concat(this.expr.find(e))),t},n.prototype.toString=function(){return this.fn.toString()},t.exports=n},{"../../util/error.js":197,"./Node.js":101}],100:[function(e,t){function n(e){this.nodes=e||[]}function r(e){for(var t=[],n=e.length,r=0;n>r;r++){for(var i=e[r],a=i.length,s=null,l=null,f=0;a>f;f++){var m,p=o.clone(i[f]);if(p instanceof u){if(m=p.size(),p=p.valueOf(),1==m.length)p=[p],m=[1,m[0]];else if(m.length>2)throw new Error("Cannot merge a multi dimensional matrix")}else p instanceof c?(p=[p.valueOf()],m=[1,p[0].length]):Array.isArray(p)?(m=[1,p.length],p=[p]):(m=[1,1],p=[[p]]);if(null==s)s=p,l=m[0];else{if(m[0]!=l)throw new Error("Dimension mismatch ("+m[0]+" != "+l+")");for(var h=0;l>h;h++)s[h]=s[h].concat(p[h])}}t=t.concat(s)}return t}var i=e("./Node.js"),o=e("../../util/object.js"),a=e("../../util/string.js"),s=e("../../type/collection.js"),u=e("../../type/Matrix.js"),c=e("../../type/Range.js");n.prototype=new i,n.prototype.eval=function(){for(var e=this.nodes,t=[],n=!1,i=0,o=e.length;o>i;i++){for(var a=e[i],c=[],l=0,f=a.length;f>l;l++){var m=a[l].eval();s.isCollection(m)&&(n=!0),c[l]=m}t[i]=c}return n&&(t=r(t)),new u(t)},n.prototype.find=function(e){var t=[];this.match(e)&&t.push(this);for(var n=this.nodes,r=0,i=n.length;i>r;r++)for(var o=n[r],a=0,s=o.length;s>a;a++)t=t.concat(o[a].find(e));return t},n.prototype.toString=function(){return a.format(this.nodes)},t.exports=n},{"../../type/Matrix.js":190,"../../type/Range.js":191,"../../type/collection.js":193,"../../util/object.js":200,"../../util/string.js":201,"./Node.js":101}],101:[function(e,t){function n(){}n.prototype.eval=function(){throw new Error("Cannot evaluate a Node interface")},n.prototype.find=function(e){return this.match(e)?[this]:[]},n.prototype.match=function(e){var t=!0;if(e&&(!e.type||this instanceof e.type||(t=!1),t&&e.properties))for(var n in e.properties)if(e.properties.hasOwnProperty(n)&&this[n]!=e.properties[n]){t=!1;break}return t},n.prototype.toString=function(){return""},t.exports=n},{}],102:[function(e,t){function n(e,t,n){this.name=e,this.fn=t,this.params=n}var r=e("./Node.js");n.prototype=new r,n.prototype.eval=function(){return this.fn.apply(this,this.params.map(function(e){return e.eval()}))},n.prototype.find=function(e){var t=[];this.match(e)&&t.push(this);var n=this.params;if(n)for(var r=0,i=n.length;i>r;r++)t=t.concat(n[r].find(e));return t},n.prototype.toString=function(){var e=this.params;switch(e.length){case 1:return"-"==this.name?"-"+e[0].toString():e[0].toString()+this.name;case 2:var t=e[0].toString();e[0]instanceof n&&(t="("+t+")");var r=e[1].toString();return e[1]instanceof n&&(r="("+r+")"),t+" "+this.name+" "+r;default:return this.name+"("+this.params.join(", ")+")"}},t.exports=n},{"./Node.js":101}],103:[function(e,t){function n(e,t,n){if(this.object=e,this.params=t,this.paramScopes=n,this.hasContextParams=!1,t)for(var r={type:o,properties:{name:"end"}},i=0,a=t.length;a>i;i++)if(t[i].find(r).length>0){this.hasContextParams=!0;break}}var r=e("../../math.js"),i=e("./Node.js"),o=e("./SymbolNode.js").SymbolNode;n.prototype=new i,n.prototype.eval=function(){var e,t,n=this.object;if(void 0==n)throw new Error("Node undefined");var i=n.eval();if(this.hasContextParams){var o,a=this.paramScopes;if(o=i.size?i.size():void 0!==i.length?[i.length]:[],a&&o)for(e=0,t=this.params.length;t>e;e++){var s=a[e];s&&s.set("end",o[e]-1)}}var u=this.params,c=[];for(e=0,t=this.params.length;t>e;e++)c[e]=u[e].eval();return"function"==typeof i?i.apply(this,c):r.subset(i,c)},n.prototype.find=function(e){var t=[];this.match(e)&&t.push(this),this.object&&(t=t.concat(this.object.find(e)));var n=this.params;if(n)for(var r=0,i=n.length;i>r;r++)t=t.concat(n[r].find(e));return t},n.prototype.toString=function(){var e=this.object?this.object.toString():"";return this.params&&(e+="("+this.params.join(", ")+")"),e},t.exports=n},{"../../math.js":186,"./Node.js":101,"./SymbolNode.js":104}],104:[function(e,t){function n(e,t){this.name=e,this.scope=t}var r=e("./Node.js");n.prototype=new r,n.prototype.eval=function(){var e=this.scope.get(this.name);if(void 0===e)throw new Error("Undefined symbol "+this.name);return e},n.prototype.toString=function(){return this.name},t.exports=n},{"./Node.js":101}],105:[function(e,t){function n(e,t,n,r,i){this.name=e,this.params=t,this.paramScopes=n,this.expr=r,this.scope=i,this.hasContextParams=!1;for(var a={type:o,properties:{name:"end"}},s=0,u=t.length;u>s;s++)if(t[s].find(a).length>0){this.hasContextParams=!0;break}}var r=e("../../math.js"),i=e("./Node.js"),o=e("./SymbolNode.js").SymbolNode;n.prototype=new i,n.prototype.eval=function(){if(void 0===this.expr)throw new Error("Undefined symbol "+this.name);var e,t=this.scope.get(this.name);if(void 0==t)throw new Error("Undefined symbol "+this.name);if(this.hasContextParams){var n,i=this.paramScopes;if(n=t.size?t.size():void 0!==t.length?[t.length]:[],i&&n)for(var o=0,a=this.params.length;a>o;o++){var s=i[o];s&&s.set("end",n[o]-1)}}var u=[];this.params.forEach(function(e){u.push(e.eval())});var c=this.expr.eval();return e=r.subset(t,u,c),this.scope.set(this.name,e),e},n.prototype.find=function(e){var t=[];this.match(e)&&t.push(this);var n=this.params;if(n)for(var r=0,i=n.length;i>r;r++)t=t.concat(n[r].find(e));return this.expr&&(t=t.concat(this.expr.find(e))),t},n.prototype.toString=function(){var e="";return e+=this.name,this.params&&this.params.length&&(e+="("+this.params.join(", ")+")"),e+=" = ",e+=this.expr.toString()},t.exports=n},{"../../math.js":186,"./Node.js":101,"./SymbolNode.js":104}],106:[function(){},{}],107:[function(e,t,n){n.AssignmentNode=e("./AssignmentNode.js"),n.BlockNode=e("./BlockNode.js"),n.ConstantNode=e("./ConstantNode.js"),n.FunctionNode=e("./FunctionNode.js"),n.MatrixNode=e("./MatrixNode.js"),n.Node=e("./Node.js"),n.OperatorNode=e("./OperatorNode.js"),n.ParamsNode=e("./ParamsNode.js"),n.SymbolNode=e("./SymbolNode.js"),n.UpdateNode=e("./UpdateNode.js"),n.handlers=e("./handlers.js")},{"./AssignmentNode.js":96,"./BlockNode.js":97,"./ConstantNode.js":98,"./FunctionNode.js":99,"./MatrixNode.js":100,"./Node.js":101,"./OperatorNode.js":102,"./ParamsNode.js":103,"./SymbolNode.js":104,"./UpdateNode.js":105,"./handlers.js":106}],108:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Complex.js"),i=(e("../../type/Matrix.js"),e("../../type/collection.js")),o=n.number.isNumber,a=r.isComplex,s=i.isCollection;t.abs=function u(e){if(1!=arguments.length)throw new n.error.ArgumentsError("abs",arguments.length,1);if(o(e))return Math.abs(e);if(a(e))return Math.sqrt(e.re*e.re+e.im*e.im);if(s(e))return i.map(e,u);if(e.valueOf()!==e)return u(e.valueOf());throw new n.error.UnsupportedTypeError("abs",e)}}},{"../../type/Complex.js":188,"../../type/Matrix.js":190,"../../type/collection.js":193,"../../util/index.js":198}],109:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Complex.js"),i=(e("../../type/Matrix.js"),e("../../type/Unit.js")),o=e("../../type/collection.js"),a=n.number.isNumber,s=n.string.isString,u=r.isComplex,c=i.isUnit,l=o.isCollection;t.add=function f(e,t){if(2!=arguments.length)throw new n.error.ArgumentsError("add",arguments.length,2);if(a(e)){if(a(t))return e+t;if(u(t))return r.create(e+t.re,t.im)}else if(u(e)){if(a(t))return r.create(e.re+t,e.im);if(u(t))return r.create(e.re+t.re,e.im+t.im)}else if(c(e)&&c(t)){if(!e.equalBase(t))throw new Error("Units do not match");if(null==e.value)throw new Error("Unit on left hand side of operator + has an undefined value");if(null==t.value)throw new Error("Unit on right hand side of operator + has an undefined value");var i=e.clone();return i.value+=t.value,i.fixPrefix=!1,i}if(s(e)||s(t))return e+t;if(l(e)||l(t))return o.map2(e,t,f);if(e.valueOf()!==e||t.valueOf()!==t)return f(e.valueOf(),t.valueOf());throw new n.error.UnsupportedTypeError("add",e,t)}}},{"../../type/Complex.js":188,"../../type/Matrix.js":190,"../../type/Unit.js":192,"../../type/collection.js":193,"../../util/index.js":198}],110:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Complex.js"),i=e("../../type/collection.js"),o=n.number.isNumber,a=i.isCollection,s=r.isComplex;t.ceil=function u(e){if(1!=arguments.length)throw new n.error.ArgumentsError("ceil",arguments.length,1);if(o(e))return Math.ceil(e);if(s(e))return r.create(Math.ceil(e.re),Math.ceil(e.im));if(a(e))return i.map(e,u);if(e.valueOf()!==e)return u(e.valueOf());throw new n.error.UnsupportedTypeError("ceil",e)}}},{"../../type/Complex.js":188,"../../type/collection.js":193,"../../util/index.js":198}],111:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Complex.js"),i=e("../../type/collection.js"),o=n.number.isNumber,a=r.isComplex,s=i.isCollection;t.cube=function u(e){if(1!=arguments.length)throw new n.error.ArgumentsError("cube",arguments.length,1);if(o(e))return e*e*e;if(a(e))return t.multiply(t.multiply(e,e),e);if(s(e))return i.map(e,u);if(e.valueOf()!==e)return u(e.valueOf());throw new n.error.UnsupportedTypeError("cube",e)}}},{"../../type/Complex.js":188,"../../type/collection.js":193,"../../util/index.js":198}],112:[function(e,t){t.exports=function(t){function n(e,t){var n=t.re*t.re+t.im*t.im;return 0!=n?i.create((e.re*t.re+e.im*t.im)/n,(e.im*t.re-e.re*t.im)/n):i.create(0!=e.re?e.re/0:0,0!=e.im?e.im/0:0)}var r=e("../../util/index.js"),i=e("../../type/Complex.js"),o=(e("../../type/Matrix.js"),e("../../type/Unit.js")),a=e("../../type/collection.js"),s=r.number.isNumber,u=i.isComplex,c=o.isUnit,l=a.isCollection;t.divide=function f(e,o){if(2!=arguments.length)throw new r.error.ArgumentsError("divide",arguments.length,2);if(s(e)){if(s(o))return e/o;if(u(o))return n(new i(e,0),o)}if(u(e)){if(s(o))return n(e,new i(o,0));if(u(o))return n(e,o)}if(c(e)&&s(o)){var m=e.clone();return m.value/=o,m}if(l(e))return l(o)?t.multiply(e,t.inv(o)):a.map2(e,o,f);if(l(o))return t.multiply(e,t.inv(o));if(e.valueOf()!==e||o.valueOf()!==o)return f(e.valueOf(),o.valueOf());throw new r.error.UnsupportedTypeError("divide",e,o)}}},{"../../type/Complex.js":188,"../../type/Matrix.js":190,"../../type/Unit.js":192,"../../type/collection.js":193,"../../util/index.js":198}],113:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/collection.js");t.edivide=function(e,i){if(2!=arguments.length)throw new n.error.ArgumentsError("edivide",arguments.length,2);return r.deepMap2(e,i,t.divide)}}},{"../../type/collection.js":193,"../../util/index.js":198}],114:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/collection.js");t.emultiply=function(e,i){if(2!=arguments.length)throw new n.error.ArgumentsError("emultiply",arguments.length,2);return r.deepMap2(e,i,t.multiply)}}},{"../../type/collection.js":193,"../../util/index.js":198}],115:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/collection.js");t.epow=function(e,i){if(2!=arguments.length)throw new n.error.ArgumentsError("epow",arguments.length,2);return r.deepMap2(e,i,t.pow)}}},{"../../type/collection.js":193,"../../util/index.js":198}],116:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Complex.js"),i=e("../../type/Unit.js"),o=e("../../type/collection.js"),a=n.number.isNumber,s=n.string.isString,u=r.isComplex,c=i.isUnit,l=o.isCollection;t.equal=function f(e,t){if(2!=arguments.length)throw new n.error.ArgumentsError("equal",arguments.length,2);if(a(e)){if(a(t))return e==t;if(u(t))return e==t.re&&0==t.im}if(u(e)){if(a(t))return e.re==t&&0==e.im;if(u(t))return e.re==t.re&&e.im==t.im}if(c(e)&&c(t)){if(!e.equalBase(t))throw new Error("Cannot compare units with different base");return e.value==t.value}if(s(e)||s(t))return e==t;if(l(e)||l(t))return o.map2(e,t,f);if(e.valueOf()!==e||t.valueOf()!==t)return f(e.valueOf(),t.valueOf());throw new n.error.UnsupportedTypeError("equal",e,t)}}},{"../../type/Complex.js":188,"../../type/Unit.js":192,"../../type/collection.js":193,"../../util/index.js":198}],117:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Complex.js"),i=(e("../../type/Matrix.js"),e("../../type/collection.js")),o=n.number.isNumber,a=r.isComplex,s=i.isCollection;t.exp=function u(e){if(1!=arguments.length)throw new n.error.ArgumentsError("exp",arguments.length,1);if(o(e))return Math.exp(e);if(a(e)){var t=Math.exp(e.re);return r.create(t*Math.cos(e.im),t*Math.sin(e.im))}if(s(e))return i.map(e,u);if(e.valueOf()!==e)return u(e.valueOf());throw new n.error.UnsupportedTypeError("exp",e)}}},{"../../type/Complex.js":188,"../../type/Matrix.js":190,"../../type/collection.js":193,"../../util/index.js":198}],118:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Complex.js"),i=e("../../type/collection.js"),o=n.number.isNumber,a=r.isComplex,s=i.isCollection;t.fix=function u(e){if(1!=arguments.length)throw new n.error.ArgumentsError("fix",arguments.length,1);if(o(e))return e>0?Math.floor(e):Math.ceil(e);if(a(e))return r.create(e.re>0?Math.floor(e.re):Math.ceil(e.re),e.im>0?Math.floor(e.im):Math.ceil(e.im));if(s(e))return i.map(e,u);if(e.valueOf()!==e)return u(e.valueOf());throw new n.error.UnsupportedTypeError("fix",e)}}},{"../../type/Complex.js":188,"../../type/collection.js":193,"../../util/index.js":198}],119:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Complex.js"),i=e("../../type/collection.js"),o=n.number.isNumber,a=r.isComplex,s=i.isCollection;t.floor=function u(e){if(1!=arguments.length)throw new n.error.ArgumentsError("floor",arguments.length,1);if(o(e))return Math.floor(e);if(a(e))return r.create(Math.floor(e.re),Math.floor(e.im));if(s(e))return i.map(e,u);if(e.valueOf()!==e)return u(e.valueOf());throw new n.error.UnsupportedTypeError("floor",e)}}},{"../../type/Complex.js":188,"../../type/collection.js":193,"../../util/index.js":198}],120:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/collection.js"),i=n.number.isNumber,o=n.number.isInteger,a=r.isCollection;t.gcd=function s(){var e,t=arguments[0],u=arguments[1];if(2==arguments.length){if(i(t)&&i(u)){if(!o(t)||!o(u))throw new Error("Parameters in function gcd must be integer numbers");for(;0!=u;)e=u,u=t%e,t=e;return Math.abs(t)}if(a(t)||a(u))return r.map2(t,u,s);if(t.valueOf()!==t||u.valueOf()!==u)return s(t.valueOf(),u.valueOf());throw new n.error.UnsupportedTypeError("gcd",t,u)}if(arguments.length>2){for(var c=1;cr;if(u(r))return e>t.abs(r)}if(u(e)){if(a(r))return t.abs(e)>r;if(u(r))return t.abs(e)>t.abs(r)}if(c(e)&&c(r)){if(!e.equalBase(r))throw new Error("Cannot compare units with different base");return e.value>r.value}if(s(e)||s(r))return e>r;if(l(e)||l(r))return o.map2(e,r,f);if(e.valueOf()!==e||r.valueOf()!==r)return f(e.valueOf(),r.valueOf());throw new n.error.UnsupportedTypeError("larger",e,r)}}},{"../../type/Complex.js":188,"../../type/Unit.js":192,"../../type/collection.js":193,"../../util/index.js":198}],122:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Complex.js"),i=e("../../type/Unit.js"),o=e("../../type/collection.js"),a=n.number.isNumber,s=n.string.isString,u=r.isComplex,c=i.isUnit,l=o.isCollection;t.largereq=function f(e,r){if(2!=arguments.length)throw new n.error.ArgumentsError("largereq",arguments.length,2);if(a(e)){if(a(r))return e>=r;if(u(r))return e>=t.abs(r)}if(u(e)){if(a(r))return t.abs(e)>=r;if(u(r))return t.abs(e)>=t.abs(r)}if(c(e)&&c(r)){if(!e.equalBase(r))throw new Error("Cannot compare units with different base");return e.value>=r.value}if(s(e)||s(r))return e>=r;if(l(e)||l(r))return o.map2(e,r,f);if(e.valueOf()!==e||r.valueOf()!==r)return f(e.valueOf(),r.valueOf());throw new n.error.UnsupportedTypeError("largereq",e,r)}}},{"../../type/Complex.js":188,"../../type/Unit.js":192,"../../type/collection.js":193,"../../util/index.js":198}],123:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/collection.js"),i=n.number.isNumber,o=n.number.isInteger,a=r.isCollection;t.lcm=function s(){var e,t=arguments[0],u=arguments[1];if(2==arguments.length){if(i(t)&&i(u)){if(!o(t)||!o(u))throw new Error("Parameters in function lcm must be integer numbers");for(var c=t*u;0!=u;)e=u,u=t%e,t=e;return Math.abs(c/t)}if(a(t)||a(u))return r.map2(t,u,s);if(t.valueOf()!==t||u.valueOf()!==u)return s(t.valueOf(),u.valueOf());throw new n.error.UnsupportedTypeError("lcm",t,u)}if(arguments.length>2){for(var l=1;l=0?Math.log(e):u(new r(e,0));if(a(e))return r.create(Math.log(Math.sqrt(e.re*e.re+e.im*e.im)),Math.atan2(e.im,e.re));if(s(e))return i.map(e,u);if(e.valueOf()!==e)return u(e.valueOf());throw new n.error.UnsupportedTypeError("log",e)}if(2==arguments.length)return t.divide(u(e),u(c));throw new n.error.ArgumentsError("log",arguments.length,1,2)}}},{"../../type/Complex.js":188,"../../type/collection.js":193,"../../util/index.js":198}],125:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Complex.js"),i=e("../../type/collection.js"),o=n.number.isNumber,a=r.isComplex,s=i.isCollection;t.log10=function u(e){if(1!=arguments.length)throw new n.error.ArgumentsError("log10",arguments.length,1);if(o(e))return e>=0?Math.log(e)/Math.LN10:u(new r(e,0));if(a(e))return r.create(Math.log(Math.sqrt(e.re*e.re+e.im*e.im))/Math.LN10,Math.atan2(e.im,e.re)/Math.LN10);if(s(e))return i.map(e,u);if(e.valueOf()!==e)return u(e.valueOf());throw new n.error.UnsupportedTypeError("log10",e)}}},{"../../type/Complex.js":188,"../../type/collection.js":193,"../../util/index.js":198}],126:[function(e,t){t.exports=function(t){function n(e,t){if(t>0)return e>0?e%t:0==e?0:e-t*Math.floor(e/t);if(0==t)return e;throw new Error("Cannot calculate mod for a negative divisor")}var r=e("../../util/index.js"),i=e("../../type/collection.js"),o=r.number.isNumber,a=i.isCollection;t.mod=function s(e,t){if(2!=arguments.length)throw new r.error.ArgumentsError("mod",arguments.length,2);if(o(e)&&o(t))return n(e,t);if(a(e)||a(t))return i.map2(e,t,s);if(e.valueOf()!==e||t.valueOf()!==t)return s(e.valueOf(),t.valueOf());throw new r.error.UnsupportedTypeError("mod",e,t)}}},{"../../type/collection.js":193,"../../util/index.js":198}],127:[function(e,t){t.exports=function(t){function n(e,t){return 0==e.im?0==t.im?e.re*t.re:0==t.re?new i(0,e.re*t.im):new i(e.re*t.re,e.re*t.im):0==e.re?0==t.im?new i(0,e.im*t.re):0==t.re?-e.im*t.im:new i(-e.im*t.im,e.im*t.re):0==t.im?new i(e.re*t.re,e.im*t.re):0==t.re?new i(-e.im*t.im,e.re*t.im):new i(e.re*t.re-e.im*t.im,e.re*t.im+e.im*t.re)}var r=e("../../util/index.js"),i=e("../../type/Complex.js"),o=e("../../type/Matrix.js"),a=e("../../type/Unit.js"),s=e("../../type/collection.js"),u=r.array,c=r.number.isNumber,l=i.isComplex,f=Array.isArray,m=a.isUnit;t.multiply=function p(e,a){if(2!=arguments.length)throw new r.error.ArgumentsError("multiply",arguments.length,2);if(c(e)){if(c(a))return e*a;if(l(a))return n(new i(e,0),a);if(m(a))return g=a.clone(),g.value*=e,g}else if(l(e)){if(c(a))return n(e,new i(a,0));if(l(a))return n(e,a)}else if(m(e)){if(c(a))return g=e.clone(),g.value*=a,g}else{if(f(e)){if(f(a)){var h=u.size(e),x=u.size(a);if(2!=h.length)throw new Error("Can only multiply a 2 dimensional matrix (A has "+h.length+" dimensions)");if(2!=x.length)throw new Error("Can only multiply a 2 dimensional matrix (B has "+x.length+" dimensions)");if(h[1]!=x[0])throw new RangeError("Dimensions mismatch in multiplication. Columns of A must match rows of B (A is "+h[0]+"x"+h[1]+", B is "+x[0]+"x"+x[1]+", "+x[1]+" != "+x[0]+")");for(var g=[],d=h[0],y=x[1],v=h[1],j=0;d>j;j++){g[j]=[];for(var w=0;y>w;w++){for(var b=null,E=0;v>E;E++){var N=p(e[j][E],a[E][w]);b=null==b?N:t.add(b,N)}g[j][w]=b}}return g}return a instanceof o?new o(p(e.valueOf(),a.valueOf())):s.map2(e,a,p)}if(e instanceof o)return new o(p(e.valueOf(),a.valueOf()))}if(f(a))return s.map2(e,a,p);if(a instanceof o)return new o(p(e.valueOf(),a.valueOf()));if(e.valueOf()!==e||a.valueOf()!==a)return p(e.valueOf(),a.valueOf());throw new r.error.UnsupportedTypeError("multiply",e,a)}}},{"../../type/Complex.js":188,"../../type/Matrix.js":190,"../../type/Unit.js":192,"../../type/collection.js":193,"../../util/index.js":198}],128:[function(e,t){t.exports=function(t){function n(e,n){var r=t.log(e),i=t.multiply(r,n);return t.exp(i)}var r=e("../../util/index.js"),i=e("../../type/Complex.js"),o=e("../../type/Matrix.js"),a=r.array,s=r.number.isNumber,u=Array.isArray,c=r.number.isInteger,l=i.isComplex;t.pow=function f(e,m){if(2!=arguments.length)throw new r.error.ArgumentsError("pow",arguments.length,2);if(s(e)){if(s(m))return c(m)||e>=0?Math.pow(e,m):n(new i(e,0),new i(m,0));if(l(m))return n(new i(e,0),m)}else if(l(e)){if(s(m))return n(e,new i(m,0));if(l(m))return n(e,m)}else{if(u(e)){if(!s(m)||!c(m)||0>m)throw new TypeError("For A^b, b must be a positive integer (value is "+m+")");var p=a.size(e);if(2!=p.length)throw new Error("For A^b, A must be 2 dimensional (A has "+p.length+" dimensions)");if(p[0]!=p[1])throw new Error("For A^b, A must be square (size is "+p[0]+"x"+p[1]+")");if(0==m)return t.eye(p[0]);for(var h=e,x=1;m>x;x++)h=t.multiply(e,h);return h}if(e instanceof o)return new o(f(e.valueOf(),m))}if(e.valueOf()!==e||m.valueOf()!==m)return f(e.valueOf(),m.valueOf());throw new r.error.UnsupportedTypeError("pow",e,m)}}},{"../../type/Complex.js":188,"../../type/Matrix.js":190,"../../util/index.js":198}],129:[function(e,t){t.exports=function(t){function n(e,t){if(t){var n=Math.pow(10,t);return Math.round(e*n)/n}return Math.round(e)}var r=e("../../util/index.js"),i=e("../../type/Complex.js"),o=e("../../type/collection.js"),a=r.number.isNumber,s=i.isComplex,u=o.isCollection;t.round=function c(e,t){if(1!=arguments.length&&2!=arguments.length)throw new r.error.ArgumentsError("round",arguments.length,1,2);if(void 0==t){if(a(e))return Math.round(e);if(s(e))return i.create(Math.round(e.re),Math.round(e.im));if(u(e))return o.map(e,c);if(e.valueOf()!==e)return c(e.valueOf());throw new r.error.UnsupportedTypeError("round",e)}if(!a(t))throw new TypeError("Number of decimals in function round must be an integer");if(t!==Math.round(t))throw new TypeError("Number of decimals in function round must be integer");if(0>t||t>9)throw new Error("Number of decimals in function round must be in te range of 0-9");if(a(e))return n(e,t);if(s(e))return i.create(n(e.re,t),n(e.im,t));if(u(e)||u(t))return o.map2(e,t,c);if(e.valueOf()!==e||t.valueOf()!==t)return c(e.valueOf(),t.valueOf());throw new r.error.UnsupportedTypeError("round",e,t)}}},{"../../type/Complex.js":188,"../../type/collection.js":193,"../../util/index.js":198}],130:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Complex.js"),i=e("../../type/collection.js"),o=n.number,a=n.number.isNumber,s=r.isComplex,u=i.isCollection;t.sign=function c(e){if(1!=arguments.length)throw new n.error.ArgumentsError("sign",arguments.length,1);if(a(e))return o.sign(e);if(s(e)){var t=Math.sqrt(e.re*e.re+e.im*e.im);return r.create(e.re/t,e.im/t)}if(u(e))return i.map(e,c);if(e.valueOf()!==e)return c(e.valueOf());throw new n.error.UnsupportedTypeError("sign",e)}}},{"../../type/Complex.js":188,"../../type/collection.js":193,"../../util/index.js":198}],131:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Complex.js"),i=e("../../type/Unit.js"),o=e("../../type/collection.js"),a=n.number.isNumber,s=n.string.isString,u=r.isComplex,c=i.isUnit,l=o.isCollection;t.smaller=function f(e,r){if(2!=arguments.length)throw new n.error.ArgumentsError("smaller",arguments.length,2);if(a(e)){if(a(r))return r>e;if(u(r))return ee;if(l(e)||l(r))return o.map2(e,r,f);if(e.valueOf()!==e||r.valueOf()!==r)return f(e.valueOf(),r.valueOf());throw new n.error.UnsupportedTypeError("smaller",e,r)}}},{"../../type/Complex.js":188,"../../type/Unit.js":192,"../../type/collection.js":193,"../../util/index.js":198}],132:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Complex.js"),i=e("../../type/Unit.js"),o=e("../../type/collection.js"),a=n.number.isNumber,s=n.string.isString,u=r.isComplex,c=i.isUnit,l=o.isCollection;t.smallereq=function f(e,r){if(2!=arguments.length)throw new n.error.ArgumentsError("smallereq",arguments.length,2);if(a(e)){if(a(r))return r>=e;if(u(r))return e<=t.abs(r)}if(u(e)){if(a(r))return t.abs(e)<=r;if(u(r))return t.abs(e)<=t.abs(r)}if(c(e)&&c(r)){if(!e.equalBase(r))throw new Error("Cannot compare units with different base");return e.value<=r.value}if(s(e)||s(r))return r>=e;if(l(e)||l(r))return o.map2(e,r,f);if(e.valueOf()!==e||r.valueOf()!==r)return f(e.valueOf(),r.valueOf());throw new n.error.UnsupportedTypeError("smallereq",e,r)}}},{"../../type/Complex.js":188,"../../type/Unit.js":192,"../../type/collection.js":193,"../../util/index.js":198}],133:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Complex.js"),i=e("../../type/collection.js"),o=n.number.isNumber,a=r.isComplex,s=i.isCollection;t.sqrt=function u(e){if(1!=arguments.length)throw new n.error.ArgumentsError("sqrt",arguments.length,1);if(o(e))return e>=0?Math.sqrt(e):u(new r(e,0));if(a(e)){var t=Math.sqrt(e.re*e.re+e.im*e.im);return e.im>=0?r.create(.5*Math.sqrt(2*(t+e.re)),.5*Math.sqrt(2*(t-e.re))):r.create(.5*Math.sqrt(2*(t+e.re)),-.5*Math.sqrt(2*(t-e.re)))}if(s(e))return i.map(e,u);if(e.valueOf()!==e)return u(e.valueOf());throw new n.error.UnsupportedTypeError("sqrt",e)}}},{"../../type/Complex.js":188,"../../type/collection.js":193,"../../util/index.js":198}],134:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Complex.js"),i=e("../../type/collection.js"),o=n.number.isNumber,a=r.isComplex,s=i.isCollection;t.square=function u(e){if(1!=arguments.length)throw new n.error.ArgumentsError("square",arguments.length,1);if(o(e))return e*e;if(a(e))return t.multiply(e,e);if(s(e))return i.map(e,u);if(e.valueOf()!==e)return u(e.valueOf()); +throw new n.error.UnsupportedTypeError("square",e)}}},{"../../type/Complex.js":188,"../../type/collection.js":193,"../../util/index.js":198}],135:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Complex.js"),i=(e("../../type/Matrix.js"),e("../../type/Unit.js")),o=e("../../type/collection.js"),a=n.number.isNumber,s=(n.string.isString,r.isComplex),u=i.isUnit,c=o.isCollection;t.subtract=function l(e,t){if(2!=arguments.length)throw new n.error.ArgumentsError("subtract",arguments.length,2);if(a(e)){if(a(t))return e-t;if(s(t))return r.create(e-t.re,-t.im)}else if(s(e)){if(a(t))return r.create(e.re-t,e.im);if(s(t))return r.create(e.re-t.re,e.im-t.im)}else if(u(e)&&u(t)){if(!e.equalBase(t))throw new Error("Units do not match");if(null==e.value)throw new Error("Unit on left hand side of operator - has an undefined value");if(null==t.value)throw new Error("Unit on right hand side of operator - has an undefined value");var i=e.clone();return i.value-=t.value,i.fixPrefix=!1,i}if(c(e)||c(t))return o.map2(e,t,l);if(e.valueOf()!==e||t.valueOf()!==t)return l(e.valueOf(),t.valueOf());throw new n.error.UnsupportedTypeError("subtract",e,t)}}},{"../../type/Complex.js":188,"../../type/Matrix.js":190,"../../type/Unit.js":192,"../../type/collection.js":193,"../../util/index.js":198}],136:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Complex.js"),i=e("../../type/Unit.js"),o=e("../../type/collection.js"),a=n.number.isNumber,s=r.isComplex,u=i.isUnit,c=o.isCollection;t.unary=function l(e){if(1!=arguments.length)throw new n.error.ArgumentsError("unary",arguments.length,1);if(a(e))return-e;if(s(e))return r.create(-e.re,-e.im);if(u(e)){var t=e.clone();return t.value=-e.value,t}if(c(e))return o.map(e,l);if(e.valueOf()!==e)return l(e.valueOf());throw new n.error.UnsupportedTypeError("unary",e)}}},{"../../type/Complex.js":188,"../../type/Unit.js":192,"../../type/collection.js":193,"../../util/index.js":198}],137:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Complex.js"),i=e("../../type/Unit.js"),o=e("../../type/collection.js"),a=n.number.isNumber,s=n.string.isString,u=r.isComplex,c=i.isUnit,l=o.isCollection;t.unequal=function f(e,t){if(2!=arguments.length)throw new n.error.ArgumentsError("unequal",arguments.length,2);if(a(e)){if(a(t))return e!=t;if(u(t))return e!=t.re||0!=t.im}if(u(e)){if(a(t))return e.re!=t||0!=e.im;if(u(t))return e.re!=t.re||e.im!=t.im}if(c(e)&&c(t)){if(!e.equalBase(t))throw new Error("Cannot compare units with different base");return e.value!=t.value}if(s(e)||s(t))return e!=t;if(l(e)||l(t))return o.map2(e,t,f);if(e.valueOf()!==e||t.valueOf()!==t)return f(e.valueOf(),t.valueOf());throw new n.error.UnsupportedTypeError("unequal",e,t)}}},{"../../type/Complex.js":188,"../../type/Unit.js":192,"../../type/collection.js":193,"../../util/index.js":198}],138:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=n.number.isNumber,i=n.number.isInteger;t.xgcd=function o(e,t){if(2==arguments.length){if(r(e)&&r(t)){if(!i(e)||!i(t))throw new Error("Parameters in function xgcd must be integer numbers");if(0==t)return[e,1,0];var a=o(t,e%t),s=a[0],u=a[1],c=a[2];return[s,c,u-c*Math.floor(e/t)]}throw new n.error.UnsupportedTypeError("xgcd",e,t)}throw new SyntaxError("Function xgcd expects two arguments")}}},{"../../util/index.js":198}],139:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Complex.js"),i=e("../../type/collection.js"),o=n.number.isNumber,a=i.isCollection,s=r.isComplex;t.arg=function u(e){if(1!=arguments.length)throw new n.error.ArgumentsError("arg",arguments.length,1);return o(e)?Math.atan2(0,e):s(e)?Math.atan2(e.im,e.re):a(e)?i.map(e,u):e.valueOf()!==e?u(e.valueOf()):t.atan2(0,e)}}},{"../../type/Complex.js":188,"../../type/collection.js":193,"../../util/index.js":198}],140:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Complex.js"),i=e("../../type/collection.js"),o=n.object,a=n.number.isNumber,s=i.isCollection,u=r.isComplex;t.conj=function c(e){if(1!=arguments.length)throw new n.error.ArgumentsError("conj",arguments.length,1);return a(e)?e:u(e)?r.create(e.re,-e.im):s(e)?i.map(e,c):e.valueOf()!==e?c(e.valueOf()):o.clone(e)}}},{"../../type/Complex.js":188,"../../type/collection.js":193,"../../util/index.js":198}],141:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Complex.js"),i=e("../../type/collection.js"),o=n.number.isNumber,a=i.isCollection,s=r.isComplex;t.im=function u(e){if(1!=arguments.length)throw new n.error.ArgumentsError("im",arguments.length,1);return o(e)?0:s(e)?e.im:a(e)?i.map(e,u):e.valueOf()!==e?u(e.valueOf()):0}}},{"../../type/Complex.js":188,"../../type/collection.js":193,"../../util/index.js":198}],142:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Complex.js"),i=e("../../type/collection.js"),o=n.object,a=n.number.isNumber,s=i.isCollection,u=r.isComplex;t.re=function c(e){if(1!=arguments.length)throw new n.error.ArgumentsError("re",arguments.length,1);return a(e)?e:u(e)?e.re:s(e)?i.map(e,c):e.valueOf()!==e?c(e.valueOf()):o.clone(e)}}},{"../../type/Complex.js":188,"../../type/collection.js":193,"../../util/index.js":198}],143:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=n.number.isNumber,i=n.string.isString;t["boolean"]=function(e){if(1!=arguments.length)throw new n.error.ArgumentsError("boolean",arguments.length,0,1);if("true"===e||e===!0)return!0;if("false"===e||e===!1)return!1;if(r(e))return 0!==e;if(i(e)){var t=e.toLowerCase();if("true"===t)return!0;if("false"===t)return!1;var o=Number(e);if(""!=e&&!isNaN(o))return 0!==o}throw new SyntaxError(e.toString()+" is no valid boolean")}}},{"../../util/index.js":198}],144:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Complex.js"),i=n.string.isString,o=r.isComplex;t.complex=function(){switch(arguments.length){case 0:return new r(0,0);case 1:var e=arguments[0];if(o(e))return e.clone();if(i(e)){var t=r.parse(e);if(t)return t;throw new SyntaxError('String "'+e+'" is no valid complex number')}throw new TypeError("Two numbers or a single string expected in function complex");case 2:return new r(arguments[0],arguments[1]);default:throw new n.error.ArgumentsError("complex",arguments.length,0,2)}}}},{"../../type/Complex.js":188,"../../util/index.js":198}],145:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Matrix.js");t.matrix=function(e){if(arguments.length>1)throw new n.error.ArgumentsError("matrix",arguments.length,0,1);return new r(e)}}},{"../../type/Matrix.js":190,"../../util/index.js":198}],146:[function(e,t){t.exports=function(t){var n=e("../../util/index.js");t.number=function(e){switch(arguments.length){case 0:return 0;case 1:var t=Number(e);if(isNaN(t)&&(t=Number(e.valueOf())),isNaN(t))throw new SyntaxError(e.toString()+" is no valid number");return t;default:throw new n.error.ArgumentsError("number",arguments.length,0,1)}}}},{"../../util/index.js":198}],147:[function(e,t){t.exports=function(t){var n=(e("../../util/index.js"),e("../../expr/Parser.js"));t.parser=function(){return new n}}},{"../../expr/Parser.js":92,"../../util/index.js":198}],148:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Range.js"),i=n.string.isString;t.range=function(e){switch(arguments.length){case 1:if(e instanceof r)return e.clone();if(i(e)){var t=r.parse(e);if(t)return t;throw new SyntaxError('String "'+t+'" is no valid range')}throw new TypeError("Two or three numbers or a single string expected in function range");case 2:return new r(arguments[0],null,arguments[1]);case 3:return new r(arguments[0],arguments[1],arguments[2]);default:throw new n.error.ArgumentsError("range",arguments.length,2,3)}}}},{"../../type/Range.js":191,"../../util/index.js":198}],149:[function(e,t){t.exports=function(t){function n(e){if(s(e)){for(var t=e.valueOf(),r="[",i=t.length,u=0;i>u;u++)0!=u&&(r+=", "),r+=n(t[u]);return r+="]"}return a(e)?o.format(e):e.toString()}var r=e("../../util/index.js"),i=e("../../type/collection.js"),o=r.number,a=r.number.isNumber,s=i.isCollection;t.string=function(e){switch(arguments.length){case 0:return"";case 1:return n(e);default:throw new r.error.ArgumentsError("string",arguments.length,0,1)}}}},{"../../type/collection.js":193,"../../util/index.js":198}],150:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Unit.js"),i=n.string.isString;t.unit=function(){switch(arguments.length){case 1:var e=arguments[0];if(e instanceof r)return e.clone();if(i(e)){if(r.isPlainUnit(e))return new r(null,e);var t=r.parse(e);if(t)return t;throw new SyntaxError('String "'+e+'" is no valid unit')}throw new TypeError("A string or a number and string expected in function unit");case 2:return new r(arguments[0],arguments[1]);default:throw new n.error.ArgumentsError("unit",arguments.length,1,2)}}}},{"../../type/Unit.js":192,"../../util/index.js":198}],151:[function(e,t){t.exports=function(t){function n(e,t,r,i){if(r>i){if(e.length!=t.length)throw new Error("Dimensions mismatch ("+e.length+" != "+t.length+")");for(var o=[],a=0;ae;e++){var h=arguments[e];if(h instanceof i&&(m=!0),e==o-1&&u(h)){if(t=f,f=h,!c(f)||0>f)throw new TypeError("Dimension number must be a positive integer (dim = "+f+")");if(e>0&&f>t)throw new RangeError("Dimension out of range ("+f+" > "+t+")")}else{if(!l(h))throw new r.error.UnsupportedTypeError("concat",h);var x=a.clone(h).valueOf(),g=s.size(h.valueOf());if(p[e]=x,t=f,f=g.length-1,e>0&&f!=t)throw new RangeError("Dimension mismatch ("+t+" != "+f+")")}}if(0==p.length)throw new SyntaxError("At least one matrix expected");for(var d=p.shift();p.length;)d=n(d,p.shift(),f,0);return m?new i(d):d}}},{"../../type/Matrix.js":190,"../../type/collection.js":193,"../../util/index.js":198}],152:[function(e,t){t.exports=function(t){function n(e,n,r){if(1==n)return e[0][0];if(2==n)return t.subtract(t.multiply(e[0][0],e[1][1]),t.multiply(e[1][0],e[0][1]));for(var o=1,a=0,s=0;n>s&&!(a>=r);s++){for(var u=s;0==e[u][a];)if(u++,u==n&&(u=s,a++,a==r))return i.deepEqual(e,eye(n).valueOf())?t.round(o,6):0;if(u!=s){for(var c=0;r>c;c++){var l=e[u][c];e[u][c]=e[s][c],e[s][c]=l}o*=-1}for(var f=e[s][a],c=0;r>c;c++)e[s][c]=e[s][c]/f;o*=f;for(var m=0;n>m;m++)if(m!=s)for(var p=e[m][a],c=0;r>c;c++)e[m][c]=e[m][c]-e[s][c]*p;a++}return i.deepEqual(e,t.eye(n).valueOf())?t.round(o,6):0}var r=e("../../util/index.js"),i=(e("../../type/Matrix.js"),r.object),o=r.array,a=r.string;t.det=function(e){if(1!=arguments.length)throw new r.error.ArgumentsError("det",arguments.length,1);var t=o.size(e.valueOf());switch(t.length){case 0:return i.clone(e);case 1:if(1==t[0])return i.clone(e.valueOf()[0]);throw new RangeError("Matrix must be square (size: "+a.format(t)+")");case 2:var s=t[0],u=t[1];if(s==u)return n(e.valueOf(),s,u);throw new RangeError("Matrix must be square (size: "+a.format(t)+")");default:throw new RangeError("Matrix must be two dimensional (size: "+a.format(t)+")")}}}},{"../../type/Matrix.js":190,"../../util/index.js":198}],153:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Range.js"),i=e("../../type/Matrix.js"),o=n.object,a=n.number.isNumber,s=n.number.isInteger;t.diag=function(e,t){var u,c,l,f;if(1!=arguments.length&&2!=arguments.length)throw new n.error.ArgumentsError("diag",arguments.length,1,2);if(t){if(!a(t)||!s(t))throw new TypeError("Second parameter in function diag must be an integer")}else t=0;var m=t>0?t:0,p=0>t?-t:0;e instanceof i||e instanceof r||(e=new i(e));var h;switch(e.isVector()?(e=e.toVector(),h=[e.length]):h=e.size(),h.length){case 1:c=e.valueOf();var x=new i;for(x.resize([c.length+p,c.length+m]),u=x.valueOf(),f=c.length,l=0;f>l;l++)u[l+p][l+m]=o.clone(c[l]);return x;case 2:for(c=[],u=e.valueOf(),f=Math.min(h[0]-p,h[1]-m),l=0;f>l;l++)c[l]=o.clone(u[l+p][l+m]);return new i(c);default:throw new RangeError("Matrix for function diag must be 2 dimensional")}}}},{"../../type/Matrix.js":190,"../../type/Range.js":191,"../../util/index.js":198}],154:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Matrix.js"),i=e("../../type/collection.js"),o=n.number.isNumber,a=n.number.isInteger;t.eye=function(){var e=i.argsToArray(arguments);if(0==e.length)e=[1,1];else if(1==e.length)e[1]=e[0];else if(e.length>2)throw new n.error.ArgumentsError("eye",e.length,0,2);var s=e[0],u=e[1];if(!o(s)||!a(s)||1>s)throw new Error("Parameters in function eye must be positive integers");if(u&&(!o(u)||!a(u)||1>u))throw new Error("Parameters in function eye must be positive integers");var c=new r;c.resize(e);for(var l=t.min(e),f=c.valueOf(),m=0;l>m;m++)f[m][m]=1;return c}}},{"../../type/Matrix.js":190,"../../type/collection.js":193,"../../util/index.js":198}],155:[function(e,t){t.exports=function(t){function n(e,n,r){var i,o,a,s,u;if(1==n){if(s=e[0][0],0==s)throw Error("Cannot calculate inverse, determinant is zero");return[[t.divide(1,s)]]}if(2==n){var c=t.det(e);if(0==c)throw Error("Cannot calculate inverse, determinant is zero");return[[t.divide(e[1][1],c),t.divide(t.unary(e[0][1]),c)],[t.divide(t.unary(e[1][0]),c),t.divide(e[0][0],c)]]}var l=e.concat();for(i=0;n>i;i++)l[i]=l[i].concat();for(var f=t.eye(n).valueOf(),m=0;r>m;m++){for(i=m;n>i&&0==l[i][m];)i++;if(i==n||0==l[i][m])throw Error("Cannot calculate inverse, determinant is zero");i!=m&&(u=l[m],l[m]=l[i],l[i]=u,u=f[m],f[m]=f[i],f[i]=u);var p=l[m],h=f[m];for(i=0;n>i;i++){var x=l[i],g=f[i];if(i!=m){if(0!=x[m]){for(a=t.divide(t.unary(x[m]),p[m]),o=m;r>o;o++)x[o]=t.add(x[o],t.multiply(a,p[o]));for(o=0;r>o;o++)g[o]=t.add(g[o],t.multiply(a,h[o]))}}else{for(a=p[m],o=m;r>o;o++)x[o]=t.divide(x[o],a);for(o=0;r>o;o++)g[o]=t.divide(g[o],a)}}}return f}var r=e("../../util/index.js"),i=e("../../type/Matrix.js"),o=r.string;t.inv=function(e){if(1!=arguments.length)throw new r.error.ArgumentsError("inv",arguments.length,1);var a=t.size(e).valueOf();switch(a.length){case 0:return t.divide(1,e);case 1:if(1==a[0])return e instanceof i?new i([t.divide(1,e.valueOf()[0])]):[t.divide(1,e[0])];throw new RangeError("Matrix must be square (size: "+o.format(a)+")");case 2:var s=a[0],u=a[1];if(s==u)return e instanceof i?new i(n(e.valueOf(),s,u)):n(e,s,u);throw new RangeError("Matrix must be square (size: "+o.format(a)+")");default:throw new RangeError("Matrix must be two dimensional (size: "+o.format(a)+")")}}}},{"../../type/Matrix.js":190,"../../util/index.js":198}],156:[function(e,t){t.exports=function(t){var n=(e("../../util/index.js"),e("../../type/Matrix.js")),r=e("../../type/collection.js");t.ones=function(){var e=r.argsToArray(arguments);0==e.length?e=[1,1]:1==e.length&&(e[1]=e[0]);var t=new n,i=1;return t.resize(e,i),t}}},{"../../type/Matrix.js":190,"../../type/collection.js":193,"../../util/index.js":198}],157:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Complex.js"),i=e("../../type/Unit.js"),o=e("../../type/Matrix.js"),a=n.array,s=n.number.isNumber,u=n.string.isString,c=r.isComplex,l=i.isUnit;t.size=function f(e){if(1!=arguments.length)throw new n.error.ArgumentsError("size",arguments.length,1);if(s(e)||c(e)||l(e)||null==e)return[];if(u(e))return[e.length];if(Array.isArray(e))return a.size(e);if(e instanceof o)return new o(e.size());if(e.valueOf()!==e)return f(e.valueOf());throw new n.error.UnsupportedTypeError("size",e)}}},{"../../type/Complex.js":188,"../../type/Matrix.js":190,"../../type/Unit.js":192,"../../util/index.js":198}],158:[function(e,t){t.exports=function(t){function n(e){if(1==e.length)return n(e[0]);for(var t=0,r=e.length;r>t;t++){var i=e[t];a(i)&&(e[t]=n(i))}return e}var r=e("../../util/index.js"),i=e("../../type/Matrix.js"),o=r.object,a=Array.isArray;t.squeeze=function(e){if(1!=arguments.length)throw new r.error.ArgumentsError("squeeze",arguments.length,1);return a(e)?n(o.clone(e)):e instanceof i?new i(n(e.toArray())):a(e.valueOf())?n(o.clone(e.valueOf())):o.clone(e)}}},{"../../type/Matrix.js":190,"../../util/index.js":198}],159:[function(e,t){t.exports=function(t){function n(e,t){var n,i;return f(e)||e instanceof u?(n=new s(e),i=n.get(t),i.valueOf()):e instanceof s?e.get(t):l(e)?r(e,t):(n=new s([e]),i=n.get(t),i.valueOf())}function r(e,t){var n,r;if(t=t.valueOf(),1!=t.length)throw new RangeError("Dimension mismatch ("+t.length+" != 1)");f(t)&&(t=t[0]),t=t.valueOf(),f(t)||(t=[t]);var i="",o=e.length;for(n=0,r=t.length;r>n;n++){var a=t[n];c.validateIndex(a,o),i+=e.charAt(a)}return i}function i(e,n,r){if(f(e)||e instanceof u){var i=new s(t.clone(e));return i.set(n,r),i.valueOf()}return e instanceof s?e.clone().set(n,r):l(e)?o(e,n,r):(i=new s([e]),i.set(n,r),i.isScalar()?i.toScalar():i.valueOf())}function o(e,t,n){var r,i;if(t=t.valueOf(),1!=t.length)throw new RangeError("Dimension mismatch ("+t.length+" != 1)");if(f(t)&&(t=t[0]),t=t.valueOf(),f(t)||(t=[t]),t.length!=n.length)throw new RangeError("Dimension mismatch ("+t.length+" != "+n.length+")");var o=e.length,a=[];for(r=0;o>r;r++)a[r]=e.charAt(r);for(r=0,i=t.length;i>r;r++){var s=t[r];c.validateIndex(s),a[s]=n.charAt(r)}if(a.length>o)for(r=o-1,i=a.length;i>r;r++)a[r]||(a[r]=" ");return a.join("")}var a=e("../../util/index.js"),s=e("../../type/Matrix.js"),u=e("../../type/Range.js"),c=a.array,l=a.string.isString,f=Array.isArray;t.subset=function(){switch(arguments.length){case 2:return n(arguments[0],arguments[1]);case 3:return i(arguments[0],arguments[1],arguments[2]);default:throw new a.error.ArgumentsError("subset",arguments.length,2,3)}}}},{"../../type/Matrix.js":190,"../../type/Range.js":191,"../../util/index.js":198}],160:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Matrix.js"),i=n.object,o=n.string;t.transpose=function(e){if(1!=arguments.length)throw new n.error.ArgumentsError("transpose",arguments.length,1);var a=t.size(e).valueOf();switch(a.length){case 0:return i.clone(e);case 1:return i.clone(e);case 2:for(var s,u=a[1],c=a[0],l=r.isMatrix(e),f=e.valueOf(),m=[],p=i.clone,h=0;u>h;h++){s=m[h]=[];for(var x=0;c>x;x++)s[x]=p(f[x][h])}return 0==c&&(m[0]=[]),l?new r(m):m;default:throw new RangeError("Matrix must be two dimensional (size: "+o.format(a)+")")}}}},{"../../type/Matrix.js":190,"../../util/index.js":198}],161:[function(e,t){t.exports=function(t){var n=(e("../../util/index.js"),e("../../type/Matrix.js")),r=e("../../type/collection.js");t.zeros=function(){var e=r.argsToArray(arguments);0==e.length?e=[1,1]:1==e.length&&(e[1]=e[0]);var t=new n;return t.resize(e),t}}},{"../../type/Matrix.js":190,"../../type/collection.js":193,"../../util/index.js":198}],162:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/collection.js"),i=n.number.isNumber,o=n.number.isInteger,a=r.isCollection;t.factorial=function s(e){if(1!=arguments.length)throw new n.error.ArgumentsError("factorial",arguments.length,1);if(i(e)){if(!o(e)||0>e)throw new TypeError("Positive integer value expected in function factorial");var t=e,u=t;for(t--;t>1;)u*=t,t--;return 0==u&&(u=1),u}if(a(e))return r.map(e,s);if(e.valueOf()!==e)return s(e.valueOf());throw new n.error.UnsupportedTypeError("factorial",e)}}},{"../../type/collection.js":193,"../../util/index.js":198}],163:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Matrix.js"),i=Array.isArray,o={uniform:function(){return Math.random},normal:function(){return function(){for(var e,t,n=-1;0>n||n>1;)e=Math.random(),t=Math.random(),n=1/6*Math.pow(-2*Math.log(e),.5)*Math.cos(2*Math.PI*t)+.5;return n}}};t.distribution=function(e){if(!o.hasOwnProperty(e))throw new Error("unknown distribution "+e);var t=Array.prototype.slice.call(arguments,1),a=o[e].apply(this,t);return function(e){var t={random:function(t,a,s){if(arguments.length>3)throw new n.error.ArgumentsError("random",arguments.length,0,3);if(i(t)){var u=a,c=s;return void 0===c&&(c=1),void 0===u&&(u=0),new r(o(t,u,c))}if(arguments.length>2)throw new n.error.ArgumentsError("random",arguments.length,0,2);var u=t,c=a;return void 0===c&&(c=1),void 0===u&&(u=0),u+e()*(c-u)},randomInt:function(e,t){if(arguments.length>2)throw new n.error.ArgumentsError("randomInt",arguments.length,0,2);return Math.floor(this.random(e,t))},pickRandom:function(e){if(1!==arguments.length)throw new n.error.ArgumentsError("pickRandom",arguments.length,1);return e[Math.floor(Math.random()*e.length)]}},o=function(e,n,r){var i,a,s=[];if(e=e.slice(0),e.length>1)for(a=0,i=e.shift();i>a;a++)s.push(o(e,n,r));else for(a=0,i=e.shift();i>a;a++)s.push(t.random.call(t,n,r));return s};return t}(a)};var a=t.distribution("uniform");t.random=a.random,t.randomInt=a.randomInt,t.pickRandom=a.pickRandom}},{"../../type/Matrix.js":190,"../../util/index.js":198}],164:[function(e,t){t.exports=function(t){function n(e){for(var n=e[0],r=1,i=e.length;i>r;r++){var o=e[r];t.larger(o,n)&&(n=o)}return n}function r(e,n,r){for(var i=[],o=0;r>o;o++){for(var a=e[0][o],s=1;n>s;s++){var u=e[s][o];t.larger(u,a)&&(a=u)}i[o]=a}return i}var i=(e("../../util/index.js"),e("../../type/Matrix.js")),o=e("../../type/collection.js"),a=o.isCollection;t.max=function(e){if(0==arguments.length)throw new Error("Function max requires one or more parameters (0 provided)");if(a(e)){if(arguments.length>1)throw Error("Wrong number of parameters (1 matrix or multiple scalars expected)");var o=t.size(e).valueOf();if(1==o.length){if(0==e.length)throw new Error("Cannot calculate max of an empty vector");return n(e.valueOf())}if(2==o.length){if(0==o[0]||0==o[1])throw new Error("Cannot calculate max of an empty matrix");return i.isMatrix(e)?new i(r(e.valueOf(),o[0],o[1])):r(e,o[0],o[1])}throw new RangeError("Cannot calculate max for multi dimensional matrix")}return n(arguments)}}},{"../../type/Matrix.js":190,"../../type/collection.js":193,"../../util/index.js":198}],165:[function(e,t){t.exports=function(t){function n(e){for(var n=e[0],r=1,i=e.length;i>r;r++){var o=e[r];t.smaller(o,n)&&(n=o)}return n}function r(e,n,r){for(var i=[],o=0;r>o;o++){for(var a=e[0][o],s=1;n>s;s++){var u=e[s][o];t.smaller(u,a)&&(a=u)}i[o]=a}return i}var i=(e("../../util/index.js"),e("../../type/Matrix.js")),o=e("../../type/collection.js"),a=o.isCollection;t.min=function(e){if(0==arguments.length)throw new Error("Function min requires one or more parameters (0 provided)");if(a(e)){if(arguments.length>1)throw Error("Wrong number of parameters (1 matrix or multiple scalars expected)");var o=t.size(e).valueOf();if(1==o.length){if(0==e.length)throw new Error("Cannot calculate min of an empty vector");return n(e.valueOf())}if(2==o.length){if(0==o[0]||0==o[1])throw new Error("Cannot calculate min of an empty matrix");return i.isMatrix(e)?new i(r(e.valueOf(),o[0],o[1])):r(e,o[0],o[1])}throw new RangeError("Cannot calculate min for multi dimensional matrix")}return n(arguments)}}},{"../../type/Matrix.js":190,"../../type/collection.js":193,"../../util/index.js":198}],166:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Complex.js"),i=e("../../type/collection.js"),o=n.number.isNumber,a=r.isComplex,s=i.isCollection;t.acos=function u(e){if(1!=arguments.length)throw new n.error.ArgumentsError("acos",arguments.length,1);if(o(e))return e>=-1&&1>=e?Math.acos(e):u(new r(e,0));if(a(e)){var c,l=r.create(e.im*e.im-e.re*e.re+1,-2*e.re*e.im),f=t.sqrt(l);c=f instanceof r?r.create(f.re-e.im,f.im+e.re):r.create(f-e.im,e.re);var m=t.log(c);return m instanceof r?r.create(1.5707963267948966-m.im,m.re):new r(1.5707963267948966,m)}if(s(e))return i.map(e,u);if(e.valueOf()!==e)return u(e.valueOf());throw new n.error.UnsupportedTypeError("acos",e)}}},{"../../type/Complex.js":188,"../../type/collection.js":193,"../../util/index.js":198}],167:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Complex.js"),i=e("../../type/collection.js"),o=n.number.isNumber,a=r.isComplex,s=i.isCollection;t.asin=function u(e){if(1!=arguments.length)throw new n.error.ArgumentsError("asin",arguments.length,1);if(o(e))return e>=-1&&1>=e?Math.asin(e):u(new r(e,0));if(a(e)){var c,l=e.re,f=e.im,m=r.create(f*f-l*l+1,-2*l*f),p=t.sqrt(m);c=p instanceof r?r.create(p.re-f,p.im+l):r.create(p-f,l);var h=t.log(c);return h instanceof r?r.create(h.im,-h.re):r.create(0,-h)}if(s(e))return i.map(e,u);if(e.valueOf()!==e)return u(e.valueOf());throw new n.error.UnsupportedTypeError("asin",e)}}},{"../../type/Complex.js":188,"../../type/collection.js":193,"../../util/index.js":198}],168:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Complex.js"),i=e("../../type/collection.js"),o=n.number.isNumber,a=r.isComplex,s=i.isCollection;t.atan=function u(e){if(1!=arguments.length)throw new n.error.ArgumentsError("atan",arguments.length,1);if(o(e))return Math.atan(e);if(a(e)){var c=e.re,l=e.im,f=c*c+(1-l)*(1-l),m=r.create((1-l*l-c*c)/f,-2*c/f),p=t.log(m);return p instanceof r?r.create(-.5*p.im,.5*p.re):r.create(0,.5*p)}if(s(e))return i.map(e,u);if(e.valueOf()!==e)return u(e.valueOf());throw new n.error.UnsupportedTypeError("atan",e)}}},{"../../type/Complex.js":188,"../../type/collection.js":193,"../../util/index.js":198}],169:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Complex.js"),i=e("../../type/collection.js"),o=n.number.isNumber,a=r.isComplex,s=i.isCollection;t.atan2=function u(e,t){if(2!=arguments.length)throw new n.error.ArgumentsError("atan2",arguments.length,2);if(o(e)){if(o(t))return Math.atan2(e,t)}else if(a(e)&&o(t))return Math.atan2(e.re,t);if(s(e)||s(t))return i.map2(e,t,u);if(t.valueOf()!==t||e.valueOf()!==e)return u(e.valueOf(),t.valueOf());throw new n.error.UnsupportedTypeError("atan2",e,t)}}},{"../../type/Complex.js":188,"../../type/collection.js":193,"../../util/index.js":198}],170:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Complex.js"),i=e("../../type/Unit.js"),o=e("../../type/collection.js"),a=n.number.isNumber,s=r.isComplex,u=i.isUnit,c=o.isCollection;t.cos=function l(e){if(1!=arguments.length)throw new n.error.ArgumentsError("cos",arguments.length,1);if(a(e))return Math.cos(e);if(s(e))return r.create(.5*Math.cos(e.re)*(Math.exp(-e.im)+Math.exp(e.im)),.5*Math.sin(e.re)*(Math.exp(-e.im)-Math.exp(e.im)));if(u(e)){if(!e.hasBase(i.BASE_UNITS.ANGLE))throw new TypeError("Unit in function cos is no angle");return Math.cos(e.value)}if(c(e))return o.map(e,l);if(e.valueOf()!==e)return l(e.valueOf());throw new n.error.UnsupportedTypeError("cos",e)}}},{"../../type/Complex.js":188,"../../type/Unit.js":192,"../../type/collection.js":193,"../../util/index.js":198}],171:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Complex.js"),i=e("../../type/Unit.js"),o=e("../../type/collection.js"),a=n.number.isNumber,s=r.isComplex,u=i.isUnit,c=o.isCollection;t.cot=function l(e){if(1!=arguments.length)throw new n.error.ArgumentsError("cot",arguments.length,1);if(a(e))return 1/Math.tan(e);if(s(e)){var t=Math.exp(-4*e.im)-2*Math.exp(-2*e.im)*Math.cos(2*e.re)+1;return r.create(2*Math.exp(-2*e.im)*Math.sin(2*e.re)/t,(Math.exp(-4*e.im)-1)/t)}if(u(e)){if(!e.hasBase(i.BASE_UNITS.ANGLE))throw new TypeError("Unit in function cot is no angle");return 1/Math.tan(e.value)}if(c(e))return o.map(e,l);if(e.valueOf()!==e)return l(e.valueOf());throw new n.error.UnsupportedTypeError("cot",e)}}},{"../../type/Complex.js":188,"../../type/Unit.js":192,"../../type/collection.js":193,"../../util/index.js":198}],172:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Complex.js"),i=e("../../type/Unit.js"),o=e("../../type/collection.js"),a=n.number.isNumber,s=r.isComplex,u=i.isUnit,c=o.isCollection;t.csc=function l(e){if(1!=arguments.length)throw new n.error.ArgumentsError("csc",arguments.length,1);if(a(e))return 1/Math.sin(e);if(s(e)){var t=.25*(Math.exp(-2*e.im)+Math.exp(2*e.im))-.5*Math.cos(2*e.re);return r.create(.5*Math.sin(e.re)*(Math.exp(-e.im)+Math.exp(e.im))/t,.5*Math.cos(e.re)*(Math.exp(-e.im)-Math.exp(e.im))/t)}if(u(e)){if(!e.hasBase(i.BASE_UNITS.ANGLE))throw new TypeError("Unit in function csc is no angle");return 1/Math.sin(e.value)}if(c(e))return o.map(e,l);if(e.valueOf()!==e)return l(e.valueOf());throw new n.error.UnsupportedTypeError("csc",e)}}},{"../../type/Complex.js":188,"../../type/Unit.js":192,"../../type/collection.js":193,"../../util/index.js":198}],173:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Complex.js"),i=e("../../type/Unit.js"),o=e("../../type/collection.js"),a=n.number.isNumber,s=r.isComplex,u=i.isUnit,c=o.isCollection;t.sec=function l(e){if(1!=arguments.length)throw new n.error.ArgumentsError("sec",arguments.length,1);if(a(e))return 1/Math.cos(e);if(s(e)){var t=.25*(Math.exp(-2*e.im)+Math.exp(2*e.im))+.5*Math.cos(2*e.re);return r.create(.5*Math.cos(e.re)*(Math.exp(-e.im)+Math.exp(e.im))/t,.5*Math.sin(e.re)*(Math.exp(e.im)-Math.exp(-e.im))/t)}if(u(e)){if(!e.hasBase(i.BASE_UNITS.ANGLE))throw new TypeError("Unit in function sec is no angle");return 1/Math.cos(e.value)}if(c(e))return o.map(e,l);if(e.valueOf()!==e)return l(e.valueOf());throw new n.error.UnsupportedTypeError("sec",e)}}},{"../../type/Complex.js":188,"../../type/Unit.js":192,"../../type/collection.js":193,"../../util/index.js":198}],174:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Complex.js"),i=e("../../type/Unit.js"),o=e("../../type/collection.js"),a=n.number.isNumber,s=r.isComplex,u=i.isUnit,c=o.isCollection;t.sin=function l(e){if(1!=arguments.length)throw new n.error.ArgumentsError("sin",arguments.length,1);if(a(e))return Math.sin(e);if(s(e))return r.create(.5*Math.sin(e.re)*(Math.exp(-e.im)+Math.exp(e.im)),.5*Math.cos(e.re)*(Math.exp(e.im)-Math.exp(-e.im)));if(u(e)){if(!e.hasBase(i.BASE_UNITS.ANGLE))throw new TypeError("Unit in function cos is no angle");return Math.sin(e.value)}if(c(e))return o.map(e,l);if(e.valueOf()!==e)return l(e.valueOf());throw new n.error.UnsupportedTypeError("sin",e)}}},{"../../type/Complex.js":188,"../../type/Unit.js":192,"../../type/collection.js":193,"../../util/index.js":198}],175:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Complex.js"),i=e("../../type/Unit.js"),o=e("../../type/collection.js"),a=n.number.isNumber,s=r.isComplex,u=i.isUnit,c=o.isCollection;t.tan=function l(e){if(1!=arguments.length)throw new n.error.ArgumentsError("tan",arguments.length,1);if(a(e))return Math.tan(e);if(s(e)){var t=Math.exp(-4*e.im)+2*Math.exp(-2*e.im)*Math.cos(2*e.re)+1;return r.create(2*Math.exp(-2*e.im)*Math.sin(2*e.re)/t,(1-Math.exp(-4*e.im))/t)}if(u(e)){if(!e.hasBase(i.BASE_UNITS.ANGLE))throw new TypeError("Unit in function tan is no angle");return Math.tan(e.value)}if(c(e))return o.map(e,l);if(e.valueOf()!==e)return l(e.valueOf());throw new n.error.UnsupportedTypeError("tan",e)}}},{"../../type/Complex.js":188,"../../type/Unit.js":192,"../../type/collection.js":193,"../../util/index.js":198}],176:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../type/Unit.js"),i=e("../../type/collection.js"),o=n.string.isString,a=r.isUnit,s=i.isCollection;t["in"]=function u(e,t){if(2!=arguments.length)throw new n.error.ArgumentsError("in",arguments.length,2);if(a(e)&&(a(t)||o(t)))return e["in"](t);if(s(e)||s(t))return i.map2(e,t,u);if(e.valueOf()!==e||t.valueOf()!==t)return u(e.valueOf(),t.valueOf());throw new n.error.UnsupportedTypeError("in",e,t)}}},{"../../type/Unit.js":192,"../../type/collection.js":193,"../../util/index.js":198}],177:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=n.object;t.clone=function(e){if(1!=arguments.length)throw new n.error.ArgumentsError("clone",arguments.length,1); +return r.clone(e)}}},{"../../util/index.js":198}],178:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=e("../../expr/Scope.js"),i=e("../../type/collection.js"),o=n.string.isString,a=i.isCollection;t.eval=function(e,s){if(1!=arguments.length&&2!=arguments.length)throw new n.error.ArgumentsError("eval",arguments.length,1,2);var u;if(u=s?s instanceof r?s:new r(s):new r,o(e)){var c=t.parse(e,u);return c.eval()}if(a(e))return i.map(e,function(e){var n=t.parse(e,u);return n.eval()});throw new TypeError("String or matrix expected")}}},{"../../expr/Scope.js":93,"../../type/collection.js":193,"../../util/index.js":198}],179:[function(e,t){t.exports=function(t){var n=e("../../util/index.js"),r=n.string;t.format=function(){var e=arguments.length;if(1!=e&&2!=e)throw new n.error.ArgumentsError("format",e,1,2);return r.format.apply(r.format,arguments)}}},{"../../util/index.js":198}],180:[function(e,t){t.exports=function(t){var n=(e("../../util/index.js"),e("../../type/Help.js"));t.help=function(e){if(1!=arguments.length)throw new SyntaxError("Wrong number of arguments in function help ("+arguments.length+" provided, 1 expected)");var r=null;if(e instanceof String||"string"==typeof e)r=e;else{var i;for(i in t)if(t.hasOwnProperty(i)&&e===t[i]){r=i;break}if(!r)for(i in t.type)if(t.type.hasOwnProperty(i)&&e===t.type[i]){r=i;break}}if(r){var o=t.docs[r];if(!o)throw new Error('No documentation found on "'+r+'"');return new n(o)}throw new Error('Could not find search term "'+e+'"')}}},{"../../type/Help.js":189,"../../util/index.js":198}],181:[function(e,t){t.exports=function(t){function n(e,n,r){(r.override||void 0===t[e])&&(t[e]=r.wrap&&"function"==typeof n?function(){for(var e=[],r=0,i=arguments.length;i>r;r++)e[r]=arguments[r].valueOf();return n.apply(t,e)}:n,o.createProxy(e,n))}function r(e){return"function"==typeof e||u(e)||c(e)||l(e)||f(e)}var i=e("../../util/index.js"),o=e("../../expr/Selector.js"),a=e("../../type/Complex.js"),s=e("../../type/Unit.js"),u=i.number.isNumber,c=i.string.isString,l=a.isComplex,f=s.isUnit;t["import"]=function m(o,a){var s,u={override:!1,wrap:!0};if(a&&a instanceof Object&&i.object.extend(u,a),c(o)){if("undefined"==typeof e)throw new Error("Cannot load file: require not available.");var l=e(o);m(l)}else if(r(o)){if(s=o.name,!s)throw new Error("Cannot import an unnamed function or object");(u.override||void 0===t[s])&&n(s,o,u)}else if(o instanceof Object)for(s in o)if(o.hasOwnProperty(s)){var f=o[s];r(f)?n(s,f,u):m(f)}}}},{"../../expr/Selector.js":94,"../../type/Complex.js":188,"../../type/Unit.js":192,"../../util/index.js":198}],182:[function(e,t){t.exports=function(t){function n(){ot=0,at=it.charAt(0)}function r(){ot++,at=it.charAt(ot)}function i(){return it.charAt(ot+1)}function o(){for(ut=nt.NULL,st="";" "==at||" "==at;)r();if("#"==at)for(;"\n"!=at&&""!=at;)r();if(""==at)return ut=nt.DELIMITER,void 0;var e=at+i();if(rt[e])return ut=nt.DELIMITER,st=e,r(),r(),void 0;if(rt[at])return ut=nt.DELIMITER,st=at,r(),void 0;if(s(at)){if(ut=nt.NUMBER,"."==at)st+=at,r(),u(at)||(ut=nt.UNKNOWN);else{for(;u(at);)st+=at,r();"."==at&&(st+=at,r())}for(;u(at);)st+=at,r();if("E"==at||"e"==at)for(st+=at,r(),("+"==at||"-"==at)&&(st+=at,r()),u(at)||(ut=nt.UNKNOWN);u(at);)st+=at,r()}else{if(!a(at)){for(ut=nt.UNKNOWN;""!=at;)st+=at,r();throw L('Syntax error in part "'+st+'"')}for(ut=nt.SYMBOL;a(at)||u(at);)st+=at,r()}}function a(e){return e>="a"&&"z">=e||e>="A"&&"Z">=e||"_"==e}function s(e){return e>="0"&&"9">=e||"."==e}function u(e){return e>="0"&&"9">=e}function c(e){n(),o();var t;if(t=""==st?new W(void 0):l(e),""!=st)throw ut==nt.DELIMITER?P("Unknown operator "+st):L('Unexpected part "'+st+'"');return t}function l(e){var t,n,r;for("\n"!=st&&";"!=st&&""!=st&&(t=f(e));"\n"==st||";"==st;)n||(n=new Q,t&&(r=";"!=st,n.add(t,r))),o(),"\n"!=st&&";"!=st&&""!=st&&(t=f(e),r=";"!=st,n.add(t,r));return n?n:(t||(t=f(e)),t)}function f(e){var t=m(e),n="ans";return new Y(n,t,e)}function m(e){if(ut==nt.SYMBOL&&"function"==st){if(o(),ut!=nt.SYMBOL)throw L("Function name expected");var t=st;if(o(),"("!=st)throw L("Opening parenthesis ( expected");for(var n=e.createSubScope(),r=[];;){if(o(),ut!=nt.SYMBOL)throw L("Variable name expected");if(r.push(st),o(),","!=st){if(")"==st)break;throw L('Comma , or closing parenthesis ) expected"')}}if(o(),"="!=st)throw L("Equal sign = expected");o();var i=p(n);return new K(t,r,i,n,e)}return p(e)}function p(e){var t,n,r,i,a=h(e);if("="==st){if(a instanceof X)return o(),t=a.name,n=null,i=p(e),new Y(t,i,e);if(a instanceof J&&a.object instanceof X)return o(),t=a.object.name,n=a.params,r=a.paramScopes,i=p(e),new et(t,n,r,i,e);throw L("Symbol expected at the left hand side of assignment operator =")}return a}function h(e){var n,r,i,a=[];if(n=":"==st?new W(0):x(e),":"==st){for(a.push(n);":"==st;)o(),")"==st||","==st||""==st?a.push(new X("end",e)):a.push(x(e));a.length&&(r="range",i=t.range,n=new $(r,i,a))}return n}function x(e){var n,r,i,a,s;for(n=g(e),r={"in":t["in"]};void 0!==r[st];)i=st,a=r[i],o(),s=[n,g(e)],n=new $(i,a,s);return n}function g(e){var t=d(e);return t}function d(e){var n,r,i,a,s;for(n=y(e),r={"==":t.equal,"!=":t.unequal,"<":t.smaller,">":t.larger,"<=":t.smallereq,">=":t.largereq};void 0!==r[st];)i=st,a=r[i],o(),s=[n,y(e)],n=new $(i,a,s);return n}function y(e){var n,r,i,a,s;for(n=v(e),r={"+":t.add,"-":t.subtract};void 0!==r[st];)i=st,a=r[i],o(),s=[n,v(e)],n=new $(i,a,s);return n}function v(e){var n,r,i,a,s;for(n=j(e),r={"*":t.multiply,".*":t.emultiply,"/":t.divide,"./":t.edivide,"%":t.mod,mod:t.mod};void 0!==r[st];)i=st,a=r[i],o(),s=[n,j(e)],n=new $(i,a,s);return n}function j(e){var n,r,i;return"-"==st?(n=st,r=t.unary,o(),i=[j(e)],new $(n,r,i)):w(e)}function w(e){var n,r,i,a,s,u,c;for(i=[b(e)],a=[];"^"==st||".^"==st;)a.push(st),o(),i.push(b(e));for(n=i.pop();i.length;)r=i.pop(),s=a.pop(),u="^"==s?t.pow:t.epow,c=[r,n],n=new $(s,u,c);return n}function b(e){var n,r,i,a;for(n=E(e);"!"==st;)r=st,i=t.factorial,o(),a=[n],n=new $(r,i,a);return n}function E(e){var n,r,i,a;for(n=N(e);"'"==st;)r=st,i=t.transpose,o(),a=[n],n=new $(r,i,a);return n}function N(e){var t,n,r,i;if(ut==nt.SYMBOL&&tt[st]){if(i=tt[st],o(),"("==st){if(t=[],n=[],o(),")"!=st)for(r=e.createSubScope(),n.push(r),t.push(h(r));","==st;)o(),r=e.createSubScope(),n.push(r),t.push(h(r));if(")"!=st)throw L("Parenthesis ) expected");o()}return new i(t,n)}return O(e)}function O(e){var t,n;return ut==nt.SYMBOL?(n=st,o(),t=new X(n,e),M(e,t)):C(e)}function M(e,t){for(var n,r,i;"("==st;){if(n=[],r=[],o(),")"!=st)for(i=e.createSubScope(),r.push(i),n.push(h(i));","==st;)o(),i=e.createSubScope(),r.push(i),n.push(h(i));if(")"!=st)throw L("Parenthesis ) expected");o(),t=new J(t,n,r)}return t}function C(e){var t,n,i;if('"'==st){for(n="",i="";""!=at&&('"'!=at||"\\"==i);)n+=at,i=at,r();if(o(),'"'!=st)throw L('End of string " expected');return o(),t=new W(n),t=M(e,t)}return A(e)}function A(e){var t,n,r,i,a,s;if("["==st){for(o();"\n"==st;)o();if("]"!=st){for(n=[],r=0,i=0,n[0]=[p(e)];","==st||";"==st;){for(","==st?i++:(r++,i=0,n[r]=[]),o();"\n"==st;)o();for(n[r][i]=p(e);"\n"==st;)o()}for(a=n.length,s=n.length>0?n[0].length:0,r=1;a>r;r++)if(n[r].length!=s)throw P("Number of columns must match ("+n[r].length+" != "+s+")");if("]"!=st)throw L("End of matrix ] expected");o(),t=new Z(n)}else o(),t=new Z([[]]);return t=M(e,t)}return S(e)}function S(e){var t,n,r;if(ut==nt.NUMBER){if(r="."==st?0:Number(st),o(),ut==nt.SYMBOL){if("i"==st||"I"==st)return n=new k(0,r),o(),new W(n);if(F.isPlainUnit(st))return n=new F(r,st),o(),new W(n);throw I('Unknown unit "'+st+'"')}return t=new W(r),t=M(e,t)}return T(e)}function T(e){var t;if("("==st){if(o(),t=p(e),")"!=st)throw L("Parenthesis ) expected");return o(),t=M(e,t)}return U(e)}function U(){throw""==st?L("Unexpected end of expression"):L("Value expected")}function q(){return void 0}function z(){return ot-st.length+1}function R(e){var t=q(),n=z();return void 0===t?void 0===n?e:e+" (char "+n+")":e+" (line "+t+", char "+n+")"}function L(e){return new SyntaxError(R(e))}function I(e){return new TypeError(R(e))}function P(e){return new Error(R(e))}var _=e("../../util/index.js"),B=_.string.isString,G=Array.isArray,k=e("./../../type/Complex.js"),H=e("./../../type/Matrix.js"),F=e("./../../type/Unit.js"),V=(e("./../../type/Range.js"),e("../../type/collection.js")),D=e("./../../expr/Scope.js"),Y=e("../../expr/node/AssignmentNode.js"),Q=e("../../expr/node/BlockNode.js"),W=e("../../expr/node/ConstantNode.js"),K=e("../../expr/node/FunctionNode.js"),Z=e("../../expr/node/MatrixNode.js"),$=e("../../expr/node/OperatorNode.js"),J=e("../../expr/node/ParamsNode.js"),X=e("../../expr/node/SymbolNode.js"),et=e("../../expr/node/UpdateNode.js"),tt=e("../../expr/node/handlers.js");t.parse=function(e,t){if(1!=arguments.length&&2!=arguments.length)throw new _.error.ArgumentsError("parse",arguments.length,1,2);var n;if(n=t?t instanceof D?t:new D(t):new D,B(e))return it=e||"",c(n);if(G(e)||e instanceof H)return V.map(e,function(e){return it=e||"",c(n)});throw new TypeError("String or matrix expected")};var nt={NULL:0,DELIMITER:1,NUMBER:2,SYMBOL:3,UNKNOWN:4},rt={",":!0,"(":!0,")":!0,"[":!0,"]":!0,'"':!0,"\n":!0,";":!0,"+":!0,"-":!0,"*":!0,".*":!0,"/":!0,"./":!0,"%":!0,"^":!0,".^":!0,"!":!0,"'":!0,"=":!0,":":!0,"==":!0,"!=":!0,"<":!0,">":!0,"<=":!0,">=":!0},it="",ot=0,at="",st="",ut=nt.NULL}},{"../../expr/node/AssignmentNode.js":96,"../../expr/node/BlockNode.js":97,"../../expr/node/ConstantNode.js":98,"../../expr/node/FunctionNode.js":99,"../../expr/node/MatrixNode.js":100,"../../expr/node/OperatorNode.js":102,"../../expr/node/ParamsNode.js":103,"../../expr/node/SymbolNode.js":104,"../../expr/node/UpdateNode.js":105,"../../expr/node/handlers.js":106,"../../type/collection.js":193,"../../util/index.js":198,"./../../expr/Scope.js":93,"./../../type/Complex.js":188,"./../../type/Matrix.js":190,"./../../type/Range.js":191,"./../../type/Unit.js":192}],183:[function(e,t){t.exports=function(t){var n=e("../../expr/Selector.js");t.select=function(e){return new n(e)}}},{"../../expr/Selector.js":94}],184:[function(e,t){t.exports=function(t){var n=e("../../util/index.js");t["typeof"]=function(e){if(1!=arguments.length)throw new n.error.ArgumentsError("typeof",arguments.length,1);return n.types.type(e)}}},{"../../util/index.js":198}],185:[function(e,t){var n=t.exports=e("./math.js");n.options=e("./options"),n.expr=e("./expr/index.js"),n.type=e("./type/index.js"),n.docs=e("./docs/index.js"),e("./function/arithmetic/abs.js")(n),e("./function/arithmetic/add.js")(n),e("./function/arithmetic/add.js")(n),e("./function/arithmetic/ceil.js")(n),e("./function/arithmetic/cube.js")(n),e("./function/arithmetic/divide.js")(n),e("./function/arithmetic/edivide.js")(n),e("./function/arithmetic/emultiply.js")(n),e("./function/arithmetic/epow.js")(n),e("./function/arithmetic/equal.js")(n),e("./function/arithmetic/exp.js")(n),e("./function/arithmetic/fix.js")(n),e("./function/arithmetic/floor.js")(n),e("./function/arithmetic/gcd.js")(n),e("./function/arithmetic/larger.js")(n),e("./function/arithmetic/largereq.js")(n),e("./function/arithmetic/lcm.js")(n),e("./function/arithmetic/log.js")(n),e("./function/arithmetic/log10.js")(n),e("./function/arithmetic/mod.js")(n),e("./function/arithmetic/multiply.js")(n),e("./function/arithmetic/pow.js")(n),e("./function/arithmetic/round.js")(n),e("./function/arithmetic/sign.js")(n),e("./function/arithmetic/smaller.js")(n),e("./function/arithmetic/smallereq.js")(n),e("./function/arithmetic/sqrt.js")(n),e("./function/arithmetic/square.js")(n),e("./function/arithmetic/subtract.js")(n),e("./function/arithmetic/unary.js")(n),e("./function/arithmetic/unequal.js")(n),e("./function/arithmetic/xgcd.js")(n),e("./function/complex/arg.js")(n),e("./function/complex/conj.js")(n),e("./function/complex/re.js")(n),e("./function/complex/im.js")(n),e("./function/construction/boolean.js")(n),e("./function/construction/complex.js")(n),e("./function/construction/matrix.js")(n),e("./function/construction/number.js")(n),e("./function/construction/parser.js")(n),e("./function/construction/range.js")(n),e("./function/construction/string.js")(n),e("./function/construction/unit.js")(n),e("./function/matrix/concat.js")(n),e("./function/matrix/det.js")(n),e("./function/matrix/diag.js")(n),e("./function/matrix/eye.js")(n),e("./function/matrix/inv.js")(n),e("./function/matrix/ones.js")(n),e("./function/matrix/size.js")(n),e("./function/matrix/squeeze.js")(n),e("./function/matrix/subset.js")(n),e("./function/matrix/transpose.js")(n),e("./function/matrix/zeros.js")(n),e("./function/probability/factorial.js")(n),e("./function/probability/random.js")(n),e("./function/statistics/min.js")(n),e("./function/statistics/max.js")(n),e("./function/trigonometry/acos.js")(n),e("./function/trigonometry/asin.js")(n),e("./function/trigonometry/atan.js")(n),e("./function/trigonometry/atan2.js")(n),e("./function/trigonometry/cos.js")(n),e("./function/trigonometry/cot.js")(n),e("./function/trigonometry/csc.js")(n),e("./function/trigonometry/sec.js")(n),e("./function/trigonometry/sin.js")(n),e("./function/trigonometry/tan.js")(n),e("./function/units/in.js")(n),e("./function/utils/clone.js")(n),e("./function/utils/eval.js")(n),e("./function/utils/format.js")(n),e("./function/utils/help.js")(n),e("./function/utils/import.js")(n),e("./function/utils/parse.js")(n),e("./function/utils/select.js")(n),e("./function/utils/typeof.js")(n),e("./constants.js")(n),e("./expr/Selector.js").init()},{"./constants.js":1,"./docs/index.js":91,"./expr/Selector.js":94,"./expr/index.js":95,"./function/arithmetic/abs.js":108,"./function/arithmetic/add.js":109,"./function/arithmetic/ceil.js":110,"./function/arithmetic/cube.js":111,"./function/arithmetic/divide.js":112,"./function/arithmetic/edivide.js":113,"./function/arithmetic/emultiply.js":114,"./function/arithmetic/epow.js":115,"./function/arithmetic/equal.js":116,"./function/arithmetic/exp.js":117,"./function/arithmetic/fix.js":118,"./function/arithmetic/floor.js":119,"./function/arithmetic/gcd.js":120,"./function/arithmetic/larger.js":121,"./function/arithmetic/largereq.js":122,"./function/arithmetic/lcm.js":123,"./function/arithmetic/log.js":124,"./function/arithmetic/log10.js":125,"./function/arithmetic/mod.js":126,"./function/arithmetic/multiply.js":127,"./function/arithmetic/pow.js":128,"./function/arithmetic/round.js":129,"./function/arithmetic/sign.js":130,"./function/arithmetic/smaller.js":131,"./function/arithmetic/smallereq.js":132,"./function/arithmetic/sqrt.js":133,"./function/arithmetic/square.js":134,"./function/arithmetic/subtract.js":135,"./function/arithmetic/unary.js":136,"./function/arithmetic/unequal.js":137,"./function/arithmetic/xgcd.js":138,"./function/complex/arg.js":139,"./function/complex/conj.js":140,"./function/complex/im.js":141,"./function/complex/re.js":142,"./function/construction/boolean.js":143,"./function/construction/complex.js":144,"./function/construction/matrix.js":145,"./function/construction/number.js":146,"./function/construction/parser.js":147,"./function/construction/range.js":148,"./function/construction/string.js":149,"./function/construction/unit.js":150,"./function/matrix/concat.js":151,"./function/matrix/det.js":152,"./function/matrix/diag.js":153,"./function/matrix/eye.js":154,"./function/matrix/inv.js":155,"./function/matrix/ones.js":156,"./function/matrix/size.js":157,"./function/matrix/squeeze.js":158,"./function/matrix/subset.js":159,"./function/matrix/transpose.js":160,"./function/matrix/zeros.js":161,"./function/probability/factorial.js":162,"./function/probability/random.js":163,"./function/statistics/max.js":164,"./function/statistics/min.js":165,"./function/trigonometry/acos.js":166,"./function/trigonometry/asin.js":167,"./function/trigonometry/atan.js":168,"./function/trigonometry/atan2.js":169,"./function/trigonometry/cos.js":170,"./function/trigonometry/cot.js":171,"./function/trigonometry/csc.js":172,"./function/trigonometry/sec.js":173,"./function/trigonometry/sin.js":174,"./function/trigonometry/tan.js":175,"./function/units/in.js":176,"./function/utils/clone.js":177,"./function/utils/eval.js":178,"./function/utils/format.js":179,"./function/utils/help.js":180,"./function/utils/import.js":181,"./function/utils/parse.js":182,"./function/utils/select.js":183,"./function/utils/typeof.js":184,"./math.js":186,"./options":187,"./type/index.js":194}],186:[function(){},{}],187:[function(e,t,n){n.precision=5},{}],188:[function(e,t,n){function r(e,t){if(!(this instanceof r))throw new SyntaxError("Complex constructor must be called with the new operator");switch(arguments.length){case 0:this.re=0,this.im=0;break;case 2:if(!p(e)||!p(t))throw new TypeError("Two numbers expected in Complex constructor");this.re=e,this.im=t;break;default:if(0!=arguments.length&&2!=arguments.length)throw new SyntaxError("Two or zero arguments expected in Complex constructor")}}function i(){for(;" "==d||" "==d;)s()}function o(e){return e>="0"&&"9">=e||"."==e}function a(e){return e>="0"&&"9">=e}function s(){g++,d=x.charAt(g)}function u(e){g=e,d=x.charAt(g)}function c(){var e,t="";if(e=g,"+"==d?s():"-"==d&&(t+=d,s()),!o(d))return u(e),null;if("."==d){if(t+=d,s(),!a(d))return u(e),null}else{for(;a(d);)t+=d,s();"."==d&&(t+=d,s())}for(;a(d);)t+=d,s();if("E"==d||"e"==d){if(t+=d,s(),("+"==d||"-"==d)&&(t+=d,s()),!a(d))return u(e),null;for(;a(d);)t+=d,s()}return t}function l(){var e=x.charAt(g+1);if("I"==d||"i"==d)return s(),"1";if(!("+"!=d&&"-"!=d||"I"!=e&&"i"!=e)){var t="+"==d?"1":"-1";return s(),s(),t}return null}var f=e("../util/index.js"),m=f.number,p=f.number.isNumber,h=f.string.isString;r.isComplex=function(e){return e instanceof r};var x,g,d;r.create=function(e,t){return 0==t?e:new r(e,t)},r.parse=function(e){if(x=e,g=-1,d="",!h(x))return null;s(),i();var t=c();if(t){if("I"==d||"i"==d)return s(),i(),d?null:new r(0,Number(t));i();var n=d;if("+"!=n&&"-"!=n)return i(),d?null:new r(Number(t),0);s(),i();var o=c();if(o){if("I"!=d&&"i"!=d)return null;s()}else if(o=l(),!o)return null;return"-"==n&&(o="-"==o[0]?"+"+o.substring(1):"-"+o),s(),i(),d?null:new r(Number(t),Number(o))}return(t=l())?(i(),d?null:new r(0,Number(t))):null},r.prototype.clone=function(){return new r(this.re,this.im)},r.prototype.toString=function(){var e="",t=m.format(this.re),n=m.format(this.im);return e=0==this.im?t:0==this.re?1==this.im?"i":-1==this.im?"-i":n+"i":this.im>0?1==this.im?t+" + i":t+" + "+n+"i":-1==this.im?t+" - i":t+" - "+m.format(Math.abs(this.im))+"i"},t.exports=r,n.isComplex=r.isComplex,n.parse=r.parse,n.create=r.create,f.types.addType("complex",r)},{"../util/index.js":198}],189:[function(e,t,n){function r(e){e&&a.extend(this,e)}var i=e("../math.js"),o=e("../util/index.js"),a=o.object,s=o.string;r.isHelp=function(e){return e instanceof r},r.prototype.toString=function(){var e="\n";if(this.name&&(e+="Name: "+this.name+"\n\n"),this.category&&(e+="Category: "+this.category+"\n\n"),this.syntax&&(e+="Syntax:\n "+this.syntax.join("\n ")+"\n\n"),this.examples){var t=i.parser();e+="Examples:\n";for(var n=0;nt.length&&(i=!0);for(var o=0;ot[o])&&(t[o]=a+1,i=!0)}i&&y.resize(e,t,0);var s=t.length;n.forEach(function(t,n){s-1>n?e=e[t]:e[t]=r})}function f(e,t,n,r){var i=n[0];y.validateIndex(i),i+1>t[0]&&(y.resize(e,[i+1],0),t[0]=i+1),e[i]=r}function m(e,t,n,r){var i=n[0],o=n[1];y.validateIndex(i),y.validateIndex(o);var a=!1;i+1>(t[0]||0)&&(t[0]=i+1,a=!0),o+1>(t[1]||0)&&(t[1]=o+1,a=!0),a&&y.resize(e,t,0),e[i][o]=r}function p(e,t,n,r,i){var o=r==n.length-1,a=n[r],s=function(a,s){if(o)c(e,a,i[s]),a+1>(t[r]||0)&&(t[r]=a+1);else{var u=e[a];Array.isArray(u)||(e[a]=u=[u]),a+1>(t[r]||0)&&(t[r]=a+1),p(u,t,n,r+1,i[s])}};if(a.map){var u=a.size&&a.size()||a.length;if(u!=i.length)throw new RangeError("Dimensions mismatch ("+u+" != "+i.length+")");a.map(s)}else s(a,0)}function h(e){for(var t=0,n=e.length;n>t;t++){var r=e[t];Array.isArray(r)?h(r):void 0==r&&(e[t]=0)}}var x=e("../util/index.js"),g=e("./Range.js"),d=(x.number,x.string),y=x.array,v=x.object;r.isMatrix=function(e){return e instanceof r},r.prototype.get=function(e){var t;if(e instanceof r)t=1==e.size().length||!e.size().some(function(e){return 0!=e}),e=e.valueOf();else{if(!Array.isArray(e))throw new TypeError("Invalid index");t=!e.some(function(e){var t=y.size(e.valueOf());return 0!=t.length&&t!=[0]})}if(e.length!=this._size.length)throw new RangeError("Dimension mismatch ("+e.length+" != "+this._size.length+")");if(t)switch(e.length){case 1:return i(this._data,e[0]);case 2:return i(i(this._data,e[0]),e[1]);default:return o(this._data,e)}else switch(e.length){case 1:return new r(a(this._data,e));case 2:return new r(s(this._data,e));default:return new r(u(this._data,e,0))}},r.prototype.set=function(e,t){var n;if(e instanceof r)n=1==e.size().length||!e.size().some(function(e){return 0!=e}),e=e.valueOf();else{if(!Array.isArray(e))throw new TypeError("Invalid index");n=!e.some(function(e){var t=y.size(e.valueOf());return 0!=t.length&&t!=[0]})}if((t instanceof r||t instanceof g)&&(t=t.valueOf()),e.length=e})},r.prototype.toVector=function(){var e=0,t=void 0,n=[];if(this._size.forEach(function(r,i){r>1&&(e++,t=i),n[i]=0}),0==e){var r=this.toScalar();return r?[r]:[]}if(1==e){var i=[],o=function(e){Array.isArray(e)?e.forEach(o):i.push(e)};return o(this._data),i}return null},r.prototype.isVector=function(){var e=0;return this._size.forEach(function(t){t>1&&e++}),1>=e},r.prototype.toArray=function(){return v.clone(this._data)},r.prototype.valueOf=function(){return this._data},r.prototype.toString=function(){return d.format(this._data)},t.exports=r,n.isMatrix=r.isMatrix,x.types.addType("matrix",r)},{"../util/index.js":198,"./Range.js":191}],191:[function(e,t,n){function r(e,t,n){if(!(this instanceof r))throw new SyntaxError("Range constructor must be called with the new operator");if(null!=e&&!o.isNumber(e))throw new TypeError("Parameter start must be a number");if(null!=n&&!o.isNumber(n))throw new TypeError("Parameter end must be a number");if(null!=t&&!o.isNumber(t))throw new TypeError("Parameter step must be a number");this.start=null!=e?e:0,this.end=null!=n?n:0,this.step=null!=t?t:1}var i=e("../util/index.js"),o=i.number,a=i.string;i.array,r.parse=function(e){if(!a.isString(e))return null;var t=e.split(":"),n=t.map(function(e){return Number(e)}),i=n.some(function(e){return isNaN(e)});if(i)return null;switch(n.length){case 2:return new r(n[0],1,n[1]);case 3:return new r(n[0],n[1],n[2]);default:return null}},r.prototype.clone=function(){return new r(this.start,this.step,this.end)},r.isRange=function(e){return e instanceof r},r.prototype.size=function(){var e=0,t=Number(this.start),n=Number(this.step),r=Number(this.end),i=r-t;return o.sign(n)==o.sign(i)?e=Math.floor(i/n)+1:0==i&&(e=1),isNaN(e)&&(e=0),[e]},r.prototype.forEach=function(e){var t=Number(this.start),n=Number(this.step),r=Number(this.end),i=0;if(n>0)for(;r>=t;)e(t,i,this),t+=n,i++;else if(0>n)for(;t>=r;)e(t,i,this),t+=n,i++},r.prototype.map=function(e){var t=[];return this.forEach(function(n,r,i){t[r]=e(n,r,i)}),t},r.prototype.toArray=function(){var e=[];return this.forEach(function(t,n){e[n]=t}),e},r.prototype.toVector=r.prototype.toArray,r.prototype.isVector=function(){return!0},r.prototype.toScalar=function(){var e=this.toArray();return 1==e.length?e[0]:null},r.prototype.isScalar=function(){return 1==this.size()[0]},r.prototype.valueOf=function(){return this.toArray()},r.prototype.toString=function(){var e=o.format(Number(this.start));return 1!=this.step&&(e+=":"+o.format(Number(this.step))),e+=":"+o.format(Number(this.end))},t.exports=r,n.isRange=r.isRange,n.parse=r.parse,i.types.addType("range",r)},{"../util/index.js":198}],192:[function(e,t,n){function r(e,t){if(!(this instanceof r))throw new Error("Unit constructor must be called with the new operator");if(null!=e&&!y(e))throw new TypeError("First parameter in Unit constructor must be a number");if(null!=t&&!v(t))throw new TypeError("Second parameter in Unit constructor must be a string");if(null!=t){var n=f(t);if(!n)throw new SyntaxError('String "'+t+'" is no unit');this.unit=n.unit,this.prefix=n.prefix}else this.unit=UNIT_NONE,this.prefix=w;null!=e?(this.value=this._normalize(e),this.fixPrefix=!1):(this.value=null,this.fixPrefix=!0)}function i(){for(;" "==h||" "==h;)s()}function o(e){return e>="0"&&"9">=e||"."==e}function a(e){return e>="0"&&"9">=e}function s(){p++,h=m.charAt(p)}function u(e){p=e,h=m.charAt(p)}function c(){var e,t="";if(e=p,"+"==h?s():"-"==h&&(t+=h,s()),!o(h))return u(e),null;if("."==h){if(t+=h,s(),!a(h))return u(e),null}else{for(;a(h);)t+=h,s();"."==h&&(t+=h,s())}for(;a(h);)t+=h,s();if("E"==h||"e"==h){if(t+=h,s(),("+"==h||"-"==h)&&(t+=h,s()),!a(h))return u(e),null;for(;a(h);)t+=h,s()}return t}function l(){var e="";for(i();h&&" "!=h&&" "!=h;)e+=h,s();return e||null}function f(e){for(var t=0,n=E.length;n>t;t++){var r=E[t];if(d.endsWith(e,r.name)){var i=e.length-r.name.length,o=e.substring(0,i),a=r.prefixes[o];if(void 0!==a)return{unit:r,prefix:a}}}return null}var m,p,h,x=e("../util/index.js"),g=x.number,d=x.string,y=x.number.isNumber,v=x.string.isString;r.parse=function(e){if(m=e,p=-1,h="",!v(m))return null;s(),i();var t,n=c();return n?(t=l(),s(),i(),h?null:n&&t?new r(Number(n),t):null):(t=l(),s(),i(),h?null:new r(null,t))},r.isUnit=function(e){return e instanceof r},r.prototype.clone=function(){var e=new r;for(var t in this)this.hasOwnProperty(t)&&(e[t]=this[t]);return e},r.prototype._normalize=function(e){return(e+this.unit.offset)*this.unit.value*this.prefix.value},r.prototype._unnormalize=function(e,t){return void 0==t?e/this.unit.value/this.prefix.value-this.unit.offset:e/this.unit.value/t-this.unit.offset},r.isPlainUnit=function(e){return null!=f(e)},r.prototype.hasBase=function(e){return void 0===this.unit.base?void 0===e:this.unit.base===e},r.prototype.equalBase=function(e){return this.unit.base===e.unit.base},r.prototype.equals=function(e){return this.equalBase(e)&&this.value==e.value},r.prototype["in"]=function(e){var t;if(v(e)){if(t=new r(null,e),!this.equalBase(t))throw new Error("Units do not match");return t.value=this.value,t}if(e instanceof r){if(!this.equalBase(e))throw new Error("Units do not match");if(null!=e.value)throw new Error("Cannot convert to a unit with a value");if(null==e.unit)throw new Error("Unit expected on the right hand side of function in");return t=e.clone(),t.value=this.value,t.fixPrefix=!0,t}throw new Error("String or Unit expected as parameter")},r.prototype.toNumber=function(e){var t=this["in"](e),n=this.fixPrefix?t._bestPrefix():t.prefix;return t._unnormalize(t.value,n.value)},r.prototype.toString=function(){var e,t;if(this.fixPrefix)e=this._unnormalize(this.value),t=null!=this.value?g.format(e)+" ":"",t+=this.prefix.name+this.unit.name;else{var n=this._bestPrefix();e=this._unnormalize(this.value,n.value),t=null!=this.value?g.format(e)+" ":"",t+=n.name+this.unit.name}return t},r.prototype._bestPrefix=function(){var e=Math.abs(this.value/this.unit.value),t=w,n=Math.abs(Math.log(e/t.value)/Math.LN10-1.2),r=this.unit.prefixes;for(var i in r)if(r.hasOwnProperty(i)){var o=r[i];if(o.scientific){var a=Math.abs(Math.log(e/o.value)/Math.LN10-1.2);n>a&&(t=o,n=a)}}return t};var j={NONE:{"":{name:"",value:1,scientific:!0}},SHORT:{"":{name:"",value:1,scientific:!0},da:{name:"da",value:10,scientific:!1},h:{name:"h",value:100,scientific:!1},k:{name:"k",value:1e3,scientific:!0},M:{name:"M",value:1e6,scientific:!0},G:{name:"G",value:1e9,scientific:!0},T:{name:"T",value:1e12,scientific:!0},P:{name:"P",value:1e15,scientific:!0},E:{name:"E",value:1e18,scientific:!0},Z:{name:"Z",value:1e21,scientific:!0},Y:{name:"Y",value:1e24,scientific:!0},d:{name:"d",value:.1,scientific:!1},c:{name:"c",value:.01,scientific:!1},m:{name:"m",value:.001,scientific:!0},u:{name:"u",value:1e-6,scientific:!0},n:{name:"n",value:1e-9,scientific:!0},p:{name:"p",value:1e-12,scientific:!0},f:{name:"f",value:1e-15,scientific:!0},a:{name:"a",value:1e-18,scientific:!0},z:{name:"z",value:1e-21,scientific:!0},y:{name:"y",value:1e-24,scientific:!0}},LONG:{"":{name:"",value:1,scientific:!0},deca:{name:"deca",value:10,scientific:!1},hecto:{name:"hecto",value:100,scientific:!1},kilo:{name:"kilo",value:1e3,scientific:!0},mega:{name:"mega",value:1e6,scientific:!0},giga:{name:"giga",value:1e9,scientific:!0},tera:{name:"tera",value:1e12,scientific:!0},peta:{name:"peta",value:1e15,scientific:!0},exa:{name:"exa",value:1e18,scientific:!0},zetta:{name:"zetta",value:1e21,scientific:!0},yotta:{name:"yotta",value:1e24,scientific:!0},deci:{name:"deci",value:.1,scientific:!1},centi:{name:"centi",value:.01,scientific:!1},milli:{name:"milli",value:.001,scientific:!0},micro:{name:"micro",value:1e-6,scientific:!0},nano:{name:"nano",value:1e-9,scientific:!0},pico:{name:"pico",value:1e-12,scientific:!0},femto:{name:"femto",value:1e-15,scientific:!0},atto:{name:"atto",value:1e-18,scientific:!0},zepto:{name:"zepto",value:1e-21,scientific:!0},yocto:{name:"yocto",value:1e-24,scientific:!0}},BINARY_SHORT:{"":{name:"",value:1,scientific:!0},k:{name:"k",value:1024,scientific:!0},M:{name:"M",value:Math.pow(1024,2),scientific:!0},G:{name:"G",value:Math.pow(1024,3),scientific:!0},T:{name:"T",value:Math.pow(1024,4),scientific:!0},P:{name:"P",value:Math.pow(1024,5),scientific:!0},E:{name:"E",value:Math.pow(1024,6),scientific:!0},Z:{name:"Z",value:Math.pow(1024,7),scientific:!0},Y:{name:"Y",value:Math.pow(1024,8),scientific:!0},Ki:{name:"Ki",value:1024,scientific:!0},Mi:{name:"Mi",value:Math.pow(1024,2),scientific:!0},Gi:{name:"Gi",value:Math.pow(1024,3),scientific:!0},Ti:{name:"Ti",value:Math.pow(1024,4),scientific:!0},Pi:{name:"Pi",value:Math.pow(1024,5),scientific:!0},Ei:{name:"Ei",value:Math.pow(1024,6),scientific:!0},Zi:{name:"Zi",value:Math.pow(1024,7),scientific:!0},Yi:{name:"Yi",value:Math.pow(1024,8),scientific:!0}},BINARY_LONG:{"":{name:"",value:1,scientific:!0},kilo:{name:"kilo",value:1024,scientific:!0},mega:{name:"mega",value:Math.pow(1024,2),scientific:!0},giga:{name:"giga",value:Math.pow(1024,3),scientific:!0},tera:{name:"tera",value:Math.pow(1024,4),scientific:!0},peta:{name:"peta",value:Math.pow(1024,5),scientific:!0},exa:{name:"exa",value:Math.pow(1024,6),scientific:!0},zetta:{name:"zetta",value:Math.pow(1024,7),scientific:!0},yotta:{name:"yotta",value:Math.pow(1024,8),scientific:!0},kibi:{name:"kibi",value:1024,scientific:!0},mebi:{name:"mebi",value:Math.pow(1024,2),scientific:!0},gibi:{name:"gibi",value:Math.pow(1024,3),scientific:!0},tebi:{name:"tebi",value:Math.pow(1024,4),scientific:!0},pebi:{name:"pebi",value:Math.pow(1024,5),scientific:!0},exi:{name:"exi",value:Math.pow(1024,6),scientific:!0},zebi:{name:"zebi",value:Math.pow(1024,7),scientific:!0},yobi:{name:"yobi",value:Math.pow(1024,8),scientific:!0}}},w={name:"",value:1,scientific:!0},b={NONE:{},LENGTH:{},MASS:{},TIME:{},CURRENT:{},TEMPERATURE:{},LUMINOUS_INTENSITY:{},AMOUNT_OF_SUBSTANCE:{},FORCE:{},SURFACE:{},VOLUME:{},ANGLE:{},BIT:{}}; +BASE_UNIT_NONE={},UNIT_NONE={name:"",base:BASE_UNIT_NONE,value:1,offset:0};var E=[{name:"meter",base:b.LENGTH,prefixes:j.LONG,value:1,offset:0},{name:"inch",base:b.LENGTH,prefixes:j.NONE,value:.0254,offset:0},{name:"foot",base:b.LENGTH,prefixes:j.NONE,value:.3048,offset:0},{name:"yard",base:b.LENGTH,prefixes:j.NONE,value:.9144,offset:0},{name:"mile",base:b.LENGTH,prefixes:j.NONE,value:1609.344,offset:0},{name:"link",base:b.LENGTH,prefixes:j.NONE,value:.201168,offset:0},{name:"rod",base:b.LENGTH,prefixes:j.NONE,value:5.02921,offset:0},{name:"chain",base:b.LENGTH,prefixes:j.NONE,value:20.1168,offset:0},{name:"angstrom",base:b.LENGTH,prefixes:j.NONE,value:1e-10,offset:0},{name:"m",base:b.LENGTH,prefixes:j.SHORT,value:1,offset:0},{name:"ft",base:b.LENGTH,prefixes:j.NONE,value:.3048,offset:0},{name:"yd",base:b.LENGTH,prefixes:j.NONE,value:.9144,offset:0},{name:"mi",base:b.LENGTH,prefixes:j.NONE,value:1609.344,offset:0},{name:"li",base:b.LENGTH,prefixes:j.NONE,value:.201168,offset:0},{name:"rd",base:b.LENGTH,prefixes:j.NONE,value:5.02921,offset:0},{name:"ch",base:b.LENGTH,prefixes:j.NONE,value:20.1168,offset:0},{name:"mil",base:b.LENGTH,prefixes:j.NONE,value:254e-7,offset:0},{name:"m2",base:b.SURFACE,prefixes:j.SHORT,value:1,offset:0},{name:"sqin",base:b.SURFACE,prefixes:j.NONE,value:64516e-8,offset:0},{name:"sqft",base:b.SURFACE,prefixes:j.NONE,value:.09290304,offset:0},{name:"sqyd",base:b.SURFACE,prefixes:j.NONE,value:.83612736,offset:0},{name:"sqmi",base:b.SURFACE,prefixes:j.NONE,value:2589988.110336,offset:0},{name:"sqrd",base:b.SURFACE,prefixes:j.NONE,value:25.29295,offset:0},{name:"sqch",base:b.SURFACE,prefixes:j.NONE,value:404.6873,offset:0},{name:"sqmil",base:b.SURFACE,prefixes:j.NONE,value:6.4516e-10,offset:0},{name:"m3",base:b.VOLUME,prefixes:j.SHORT,value:1,offset:0},{name:"L",base:b.VOLUME,prefixes:j.SHORT,value:.001,offset:0},{name:"litre",base:b.VOLUME,prefixes:j.LONG,value:.001,offset:0},{name:"cuin",base:b.VOLUME,prefixes:j.NONE,value:16387064e-12,offset:0},{name:"cuft",base:b.VOLUME,prefixes:j.NONE,value:.028316846592,offset:0},{name:"cuyd",base:b.VOLUME,prefixes:j.NONE,value:.764554857984,offset:0},{name:"teaspoon",base:b.VOLUME,prefixes:j.NONE,value:5e-6,offset:0},{name:"tablespoon",base:b.VOLUME,prefixes:j.NONE,value:15e-6,offset:0},{name:"minim",base:b.VOLUME,prefixes:j.NONE,value:6.161152e-8,offset:0},{name:"fluiddram",base:b.VOLUME,prefixes:j.NONE,value:36966911e-13,offset:0},{name:"fluidounce",base:b.VOLUME,prefixes:j.NONE,value:2957353e-11,offset:0},{name:"gill",base:b.VOLUME,prefixes:j.NONE,value:.0001182941,offset:0},{name:"cup",base:b.VOLUME,prefixes:j.NONE,value:.0002365882,offset:0},{name:"pint",base:b.VOLUME,prefixes:j.NONE,value:.0004731765,offset:0},{name:"quart",base:b.VOLUME,prefixes:j.NONE,value:.0009463529,offset:0},{name:"gallon",base:b.VOLUME,prefixes:j.NONE,value:.003785412,offset:0},{name:"beerbarrel",base:b.VOLUME,prefixes:j.NONE,value:.1173478,offset:0},{name:"oilbarrel",base:b.VOLUME,prefixes:j.NONE,value:.1589873,offset:0},{name:"hogshead",base:b.VOLUME,prefixes:j.NONE,value:.238481,offset:0},{name:"fldr",base:b.VOLUME,prefixes:j.NONE,value:36966911e-13,offset:0},{name:"floz",base:b.VOLUME,prefixes:j.NONE,value:2957353e-11,offset:0},{name:"gi",base:b.VOLUME,prefixes:j.NONE,value:.0001182941,offset:0},{name:"cp",base:b.VOLUME,prefixes:j.NONE,value:.0002365882,offset:0},{name:"pt",base:b.VOLUME,prefixes:j.NONE,value:.0004731765,offset:0},{name:"qt",base:b.VOLUME,prefixes:j.NONE,value:.0009463529,offset:0},{name:"gal",base:b.VOLUME,prefixes:j.NONE,value:.003785412,offset:0},{name:"bbl",base:b.VOLUME,prefixes:j.NONE,value:.1173478,offset:0},{name:"obl",base:b.VOLUME,prefixes:j.NONE,value:.1589873,offset:0},{name:"g",base:b.MASS,prefixes:j.SHORT,value:.001,offset:0},{name:"gram",base:b.MASS,prefixes:j.LONG,value:.001,offset:0},{name:"ton",base:b.MASS,prefixes:j.SHORT,value:907.18474,offset:0},{name:"tonne",base:b.MASS,prefixes:j.SHORT,value:1e3,offset:0},{name:"grain",base:b.MASS,prefixes:j.NONE,value:6479891e-11,offset:0},{name:"dram",base:b.MASS,prefixes:j.NONE,value:.0017718451953125,offset:0},{name:"ounce",base:b.MASS,prefixes:j.NONE,value:.028349523125,offset:0},{name:"poundmass",base:b.MASS,prefixes:j.NONE,value:.45359237,offset:0},{name:"hundredweight",base:b.MASS,prefixes:j.NONE,value:45.359237,offset:0},{name:"stick",base:b.MASS,prefixes:j.NONE,value:.115,offset:0},{name:"gr",base:b.MASS,prefixes:j.NONE,value:6479891e-11,offset:0},{name:"dr",base:b.MASS,prefixes:j.NONE,value:.0017718451953125,offset:0},{name:"oz",base:b.MASS,prefixes:j.NONE,value:.028349523125,offset:0},{name:"lbm",base:b.MASS,prefixes:j.NONE,value:.45359237,offset:0},{name:"cwt",base:b.MASS,prefixes:j.NONE,value:45.359237,offset:0},{name:"s",base:b.TIME,prefixes:j.SHORT,value:1,offset:0},{name:"min",base:b.TIME,prefixes:j.NONE,value:60,offset:0},{name:"h",base:b.TIME,prefixes:j.NONE,value:3600,offset:0},{name:"seconds",base:b.TIME,prefixes:j.LONG,value:1,offset:0},{name:"second",base:b.TIME,prefixes:j.LONG,value:1,offset:0},{name:"sec",base:b.TIME,prefixes:j.LONG,value:1,offset:0},{name:"minutes",base:b.TIME,prefixes:j.NONE,value:60,offset:0},{name:"minute",base:b.TIME,prefixes:j.NONE,value:60,offset:0},{name:"hours",base:b.TIME,prefixes:j.NONE,value:3600,offset:0},{name:"hour",base:b.TIME,prefixes:j.NONE,value:3600,offset:0},{name:"day",base:b.TIME,prefixes:j.NONE,value:86400,offset:0},{name:"days",base:b.TIME,prefixes:j.NONE,value:86400,offset:0},{name:"rad",base:b.ANGLE,prefixes:j.NONE,value:1,offset:0},{name:"deg",base:b.ANGLE,prefixes:j.NONE,value:.017453292519943295,offset:0},{name:"grad",base:b.ANGLE,prefixes:j.NONE,value:.015707963267948967,offset:0},{name:"cycle",base:b.ANGLE,prefixes:j.NONE,value:6.283185307179586,offset:0},{name:"A",base:b.CURRENT,prefixes:j.SHORT,value:1,offset:0},{name:"ampere",base:b.CURRENT,prefixes:j.LONG,value:1,offset:0},{name:"K",base:b.TEMPERATURE,prefixes:j.NONE,value:1,offset:0},{name:"degC",base:b.TEMPERATURE,prefixes:j.NONE,value:1,offset:273.15},{name:"degF",base:b.TEMPERATURE,prefixes:j.NONE,value:1/1.8,offset:459.67},{name:"degR",base:b.TEMPERATURE,prefixes:j.NONE,value:1/1.8,offset:0},{name:"kelvin",base:b.TEMPERATURE,prefixes:j.NONE,value:1,offset:0},{name:"celsius",base:b.TEMPERATURE,prefixes:j.NONE,value:1,offset:273.15},{name:"fahrenheit",base:b.TEMPERATURE,prefixes:j.NONE,value:1/1.8,offset:459.67},{name:"rankine",base:b.TEMPERATURE,prefixes:j.NONE,value:1/1.8,offset:0},{name:"mol",base:b.AMOUNT_OF_SUBSTANCE,prefixes:j.NONE,value:1,offset:0},{name:"mole",base:b.AMOUNT_OF_SUBSTANCE,prefixes:j.NONE,value:1,offset:0},{name:"cd",base:b.LUMINOUS_INTENSITY,prefixes:j.NONE,value:1,offset:0},{name:"candela",base:b.LUMINOUS_INTENSITY,prefixes:j.NONE,value:1,offset:0},{name:"N",base:b.FORCE,prefixes:j.SHORT,value:1,offset:0},{name:"newton",base:b.FORCE,prefixes:j.LONG,value:1,offset:0},{name:"lbf",base:b.FORCE,prefixes:j.NONE,value:4.4482216152605,offset:0},{name:"poundforce",base:b.FORCE,prefixes:j.NONE,value:4.4482216152605,offset:0},{name:"b",base:b.BIT,prefixes:j.BINARY_SHORT,value:1,offset:0},{name:"bits",base:b.BIT,prefixes:j.BINARY_LONG,value:1,offset:0},{name:"B",base:b.BIT,prefixes:j.BINARY_SHORT,value:8,offset:0},{name:"bytes",base:b.BIT,prefixes:j.BINARY_LONG,value:8,offset:0}];r.PREFIXES=j,r.BASE_UNITS=b,r.UNITS=E,t.exports=r,n.isUnit=r.isUnit,n.isPlainUnit=r.isPlainUnit,n.parse=r.parse,x.types.addType("unit",r)},{"../util/index.js":198}],193:[function(e,t,n){var r=e("../util/index.js"),i=e("./Matrix.js"),o=e("./Range.js"),a=Array.isArray;r.string.isString,n.argsToArray=function(e){var t;if(0==e.length)t=[];else if(1==e.length)t=e[0],t instanceof i&&(t=t.toVector()),t instanceof o&&(t=t.valueOf()),a(t)||(t=[t]);else{t=[];for(var n=0;nc;c++)r[c]=n(e[c],t[c])}else for(r=[],s=e.length,c=0;s>c;c++)r[c]=n(e[c],t);else if(a(t))for(r=[],s=t.length,c=0;s>c;c++)r[c]=n(e,t[c]);else r=n(e,t);return r},n.deepMap2=function c(e,t,n){var r,s,u;if(e instanceof i||t instanceof i)return new i(c(e.valueOf(),t.valueOf(),n));if(e instanceof o||t instanceof o)return c(e.valueOf(),t.valueOf(),n);if(a(e))if(a(t)){if(e.length!=t.length)throw new RangeError("Dimension mismatch ("+e.length+" != "+t.length+")");for(r=[],s=e.length,u=0;s>u;u++)r[u]=c(e[u],t[u],n)}else for(r=[],s=e.length,u=0;s>u;u++)r[u]=c(e[u],t,n);else if(a(t))for(r=[],s=t.length,u=0;s>u;u++)r[u]=c(e,t[u],n);else r=n(e,t);return r}},{"../util/index.js":198,"./Matrix.js":190,"./Range.js":191}],194:[function(e,t,n){n.Complex=e("./Complex.js"),n.Range=e("./Range.js"),n.Matrix=e("./Matrix.js"),n.Unit=e("./Unit.js"),n.Help=e("./Help.js"),n.collection=e("./collection.js")},{"./Complex.js":188,"./Help.js":189,"./Matrix.js":190,"./Range.js":191,"./Unit.js":192,"./collection.js":193}],195:[function(e,t,n){function r(e){if(Array.isArray(e)){var t=e.length;if(t){var n=r(e[0]);return 0==n[0]?[0].concat(n):[t].concat(n)}return[t]}return[]}function i(e,t,n){var r,o=e.length;if(o!=t[n])throw new RangeError("Dimension mismatch ("+o+" != "+t[n]+")");if(nr;r++){var s=e[r];if(!Array.isArray(s))throw new RangeError("Dimension mismatch ("+(t.length-1)+" < "+t.length+")");i(e[r],t,a)}}else for(r=0;o>r;r++)if(Array.isArray(e[r]))throw new RangeError("Dimension mismatch ("+(t.length+1)+" > "+t.length+")")}function o(e,t,n){if(n 0)");o(r,t,n+1)}else if(e.length)throw new RangeError("Dimension mismatch ("+e.length+" > 0)")}function a(e,t,n,r){if(!Array.isArray(e))throw new TypeError("Array expected");var i=e.length,o=t[n];if(i!=o){if(o>e.length)for(var s=e.length;o>s;s++)e[s]=r?c.clone(r):0;else e.length=t[n];i=e.length}if(ns;s++)l=e[s],Array.isArray(l)||(l=[l],e[s]=l),a(l,t,u,r)}else for(s=0;i>s;s++){for(var l=e[s];Array.isArray(l);)l=l[0];e[s]=l}}var s=e("./number"),u=e("./string"),c=e("./object");n.size=function(e){var t=r(e);return n.validate(e,t),t},n.validate=function(e,t){var r=0==t.length;if(r){if(Array.isArray(e))throw new RangeError("Dimension mismatch ("+e.length+" != 0)")}else{var a=-1!=t.indexOf(0);a?(t.forEach(function(e){if(0!=e)throw new RangeError("Invalid size, all dimensions must be either zero or non-zero (size: "+n.formatArray(t)+")")}),o(e,t,0)):i(e,t,0)}},n.validateIndex=function(e,t){if(!s.isNumber(e)||!s.isInteger(e))throw new TypeError("Index must be an integer (value: "+e+")");if(0>e)throw new RangeError("Index out of range ("+e+" < 0)");if(void 0!==t&&e>=t)throw new RangeError("Index out of range ("+e+" >= "+t+")")},n.resize=function(e,t,n){if(!Array.isArray(t))throw new TypeError("Size must be an array (size is "+c.type(t)+")");t.forEach(function(e){if(!s.isNumber(e)||!s.isInteger(e)||0>e)throw new TypeError("Invalid size, must contain positive integers (size: "+u.format(t)+")")});var r=-1!=t.indexOf(0);r&&t.forEach(function(e){if(0!=e)throw new RangeError("Invalid size, all dimensions must be either zero or non-zero (size: "+u.format(t)+")")}),a(e,t,0,n)},n.isArray=Array.isArray},{"./number":199,"./object":200,"./string":201}],196:[function(e,t,n){n.isBoolean=function(e){return e instanceof Boolean||"boolean"==typeof e}},{}],197:[function(e,t,n){var r=e("./types.js");n.UnsupportedTypeError=function(e,t){if(2==arguments.length){var n=r.type(t);this.message="Function "+e+"("+n+") not supported"}else if(arguments.length>2){for(var i=[],o=1;o.001&&1e5>r||0==r)return n.toPrecision(e,t);var i=Math.round(Math.log(r)/Math.LN10),o=e/Math.pow(10,i);return n.toPrecision(o,t)+"e"+i},n.sign=function(e){return e>0?1:0>e?-1:0},n.toPrecision=function(e,t){return void 0===t&&(t=r.precision),e.toPrecision(t).replace(i,function(e,t,n){return e.substring(0,e.length-(t.length?0:1)-n.length)})};var i=/\.(\d*?)(0+)$/g},{"../options.js":187}],200:[function(e,t,n){var r=e("./number.js"),i=e("./string.js"),o=e("./boolean.js");n.clone=function a(e){if(null==e)return e;if("function"==typeof e.clone)return e.clone();if(r.isNumber(e)||i.isString(e)||o.isBoolean(e))return e;if(Array.isArray(e))return e.map(function(e){return a(e)});if(e instanceof Object){var t={};for(var n in e)e.hasOwnProperty(n)&&(t[n]=a(e[n]))}throw new TypeError("Cannot clone "+e)},n.extend=function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);return e},n.deepExtend=function s(e,t){for(var n in t)t.hasOwnProperty(n)&&(t[n]&&t[n].constructor===Object?(void 0===e[n]&&(e[n]={}),e[n].constructor===Object?s(e[n],t[n]):e[n]=t[n]):e[n]=t[n]);return e},n.deepEqual=function(e,t){var r,i,o;if(Array.isArray(e)){if(!Array.isArray(t))return!1;for(i=0,o=e.length;o>i;i++)if(!n.deepEqual(e[i],t[i]))return!1;return!0}if(e instanceof Object){if(Array.isArray(t)||!(t instanceof Object))return!1;for(r in e)if(e.hasOwnProperty(r)&&!n.deepEqual(e[r],t[r]))return!1;for(r in t)if(t.hasOwnProperty(r)&&!n.deepEqual(e[r],t[r]))return!1;return!0}return e.valueOf()==t.valueOf()}},{"./boolean.js":196,"./number.js":199,"./string.js":201}],201:[function(e,t,n){function r(e){if(Array.isArray(e)){for(var t="[",i=e.length,o=0;i>o;o++)0!=o&&(t+=", "),t+=r(e[o]);return t+="]"}return n.format(e)}var i=e("./number.js");n.isString=function(e){return e instanceof String||"string"==typeof e},n.endsWith=function(e,t){var n=e.length-t.length,r=e.length;return e.substring(n,r)===t},n.format=function(e,t){var o=arguments.length;if(1==o){var a=arguments[0];return i.isNumber(a)?i.format(a):Array.isArray(a)?r(a):n.isString(a)?'"'+a+'"':a instanceof Object?a.toString():String(a)}if(!n.isString(e))throw new TypeError("String expected as first parameter in function format");if(!(t instanceof Object))throw new TypeError("Object expected as second parameter in function format");return e.replace(/\$([\w\.]+)/g,function(e,n){for(var r=n.split("."),i=t[r.shift()];r.length&&void 0!=i;){var o=r.shift();i=o?i[o]:i+"."}return void 0!=i?i:e})}},{"./number.js":199}],202:[function(e,t,n){n.type=function i(e){var t,i=typeof e;if("object"==i){if(null==e)return"null";if(e instanceof Boolean)return"boolean";if(e instanceof Number)return"number";if(e instanceof String)return"string";if(Array.isArray(e))return"array";if(e instanceof Date)return"date";if(e.constructor){for(t in r)if(r.hasOwnProperty(t)&&e.constructor==r[t])return t.toLowerCase();if(e.constructor.name)return e.constructor.name.toLowerCase()}}return i};var r={};n.addType=function(e,t){r[e]=t}},{}]},{},[185])(185)}),Array.prototype.indexOf||(Array.prototype.indexOf=function(e){for(var t=0;tn;++n)e.call(t||this,this[n],n,this)}),Array.isArray||(Array.isArray=function(e){return"[object Array]"===Object.prototype.toString.call(e)}),Array.prototype.map||(Array.prototype.map=function(e,t){var n,r,i;if(null==this)throw new TypeError(" this is null or not defined");var o=Object(this),a=o.length>>>0;if("function"!=typeof e)throw new TypeError(e+" is not a function");for(t&&(n=t),r=new Array(a),i=0;a>i;){var s,u;i in o&&(s=o[i],u=e.call(n,s,i,o),r[i]=u),i++}return r}),Array.prototype.every||(Array.prototype.every=function(e){"use strict";if(null==this)throw new TypeError;var t=Object(this),n=t.length>>>0;if("function"!=typeof e)throw new TypeError;for(var r=arguments[1],i=0;n>i;i++)if(i in t&&!e.call(r,t[i],i,t))return!1;return!0}),Array.prototype.some||(Array.prototype.some=function(e){"use strict";if(null==this)throw new TypeError;var t=Object(this),n=t.length>>>0;if("function"!=typeof e)throw new TypeError;for(var r=arguments[1],i=0;n>i;i++)if(i in t&&e.call(r,t[i],i,t))return!0;return!1}),Function.prototype.bind||(Function.prototype.bind=function(e){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var t=Array.prototype.slice.call(arguments,1),n=this,r=function(){},i=function(){return n.apply(this instanceof r&&e?this:e,t.concat(Array.prototype.slice.call(arguments)))};return r.prototype=this.prototype,i.prototype=new r,i}); \ No newline at end of file diff --git a/index.js b/index.js index e752b0cbc..ae3f7bd9b 100644 --- a/index.js +++ b/index.js @@ -1 +1 @@ -exports = require ('./dist/math.js'); +module.exports = require('./src/index.js'); \ No newline at end of file diff --git a/package.json b/package.json index 3b98c691b..13207e0c4 100644 --- a/package.json +++ b/package.json @@ -29,14 +29,15 @@ "dependencies": {}, "devDependencies": { "jake": ">= 0.5.9", - "tap": ">= 0.4.3", + "browserify": "2.x", + "mocha": "1.x", "numbers" : "0.4.0", "uglify-js": ">= 2.2.5", "dateable": ">= 0.1.2", "underscore": "1.4.x" }, "scripts": { - "test": "jake test --trace" + "test": "mocha test --recursive --reporter spec" }, "main": "./dist/math.js", "bin": { diff --git a/src/constants.js b/src/constants.js index 8d8ed9961..21f77137a 100644 --- a/src/constants.js +++ b/src/constants.js @@ -1,22 +1,23 @@ -/** - * mathjs constants - */ -math.pi = Math.PI; -math.e = Math.E; -math.tau = Math.PI * 2; -math.i = new Complex(0, 1); +module.exports = function (math) { + var Complex = require('./type/Complex.js'); -math['Infinity']= Infinity; -math['NaN'] = NaN; -math['true'] = true; -math['false'] = false; + math.pi = Math.PI; + math.e = Math.E; + math.tau = Math.PI * 2; + math.i = new Complex(0, 1); -// uppercase constants (for compatibility with built-in Math) -math.E = Math.E; -math.LN2 = Math.LN2; -math.LN10 = Math.LN10; -math.LOG2E = Math.LOG2E; -math.LOG10E = Math.LOG10E; -math.PI = Math.PI; -math.SQRT1_2 = Math.SQRT1_2; -math.SQRT2 = Math.SQRT2; + math['Infinity'] = Infinity; + math['NaN'] = NaN; + math['true'] = true; + math['false'] = false; + + // uppercase constants (for compatibility with built-in Math) + math.E = Math.E; + math.LN2 = Math.LN2; + math.LN10 = Math.LN10; + math.LOG2E = Math.LOG2E; + math.LOG10E = Math.LOG10E; + math.PI = Math.PI; + math.SQRT1_2 = Math.SQRT1_2; + math.SQRT2 = Math.SQRT2; +}; diff --git a/src/docs/constants/Infinity.js b/src/docs/constants/Infinity.js index 904cc3ba3..181ae1693 100644 --- a/src/docs/constants/Infinity.js +++ b/src/docs/constants/Infinity.js @@ -1,4 +1,4 @@ -math.docs['Infinity'] = { +module.exports = { 'name': 'Infinity', 'category': 'Constants', 'syntax': [ diff --git a/src/docs/constants/LN10.js b/src/docs/constants/LN10.js index 397125574..f9bad91a0 100644 --- a/src/docs/constants/LN10.js +++ b/src/docs/constants/LN10.js @@ -1,4 +1,4 @@ -math.docs.LN10 = { +module.exports = { 'name': 'LN10', 'category': 'Constants', 'syntax': [ diff --git a/src/docs/constants/LN2.js b/src/docs/constants/LN2.js index 58e0418dc..fad9b55c2 100644 --- a/src/docs/constants/LN2.js +++ b/src/docs/constants/LN2.js @@ -1,4 +1,4 @@ -math.docs.LN2 = { +module.exports = { 'name': 'LN2', 'category': 'Constants', 'syntax': [ diff --git a/src/docs/constants/LOG10E.js b/src/docs/constants/LOG10E.js index a10581c3f..2b8c7da2c 100644 --- a/src/docs/constants/LOG10E.js +++ b/src/docs/constants/LOG10E.js @@ -1,4 +1,4 @@ -math.docs.LOG10E = { +module.exports = { 'name': 'LOG10E', 'category': 'Constants', 'syntax': [ diff --git a/src/docs/constants/LOG2E.js b/src/docs/constants/LOG2E.js index 3cf300a7c..ebd1fa1b1 100644 --- a/src/docs/constants/LOG2E.js +++ b/src/docs/constants/LOG2E.js @@ -1,4 +1,4 @@ -math.docs.LOG2E = { +module.exports = { 'name': 'LOG2E', 'category': 'Constants', 'syntax': [ diff --git a/src/docs/constants/NaN.js b/src/docs/constants/NaN.js index c3da35e94..afcf76a2d 100644 --- a/src/docs/constants/NaN.js +++ b/src/docs/constants/NaN.js @@ -1,4 +1,4 @@ -math.docs['NaN'] = { +module.exports = { 'name': 'NaN', 'category': 'Constants', 'syntax': [ diff --git a/src/docs/constants/SQRT1_2.js b/src/docs/constants/SQRT1_2.js index 414ac02f6..0ed86aaef 100644 --- a/src/docs/constants/SQRT1_2.js +++ b/src/docs/constants/SQRT1_2.js @@ -1,4 +1,4 @@ -math.docs.SQRT1_2 = { +module.exports = { 'name': 'SQRT1_2', 'category': 'Constants', 'syntax': [ diff --git a/src/docs/constants/SQRT2.js b/src/docs/constants/SQRT2.js index d924a93d0..d89d4c3c4 100644 --- a/src/docs/constants/SQRT2.js +++ b/src/docs/constants/SQRT2.js @@ -1,4 +1,4 @@ -math.docs.SQRT2 = { +module.exports = { 'name': 'SQRT2', 'category': 'Constants', 'syntax': [ diff --git a/src/docs/constants/e.js b/src/docs/constants/e.js index 76f68e4f9..c12df5319 100644 --- a/src/docs/constants/e.js +++ b/src/docs/constants/e.js @@ -1,4 +1,4 @@ -math.docs.e = math.docs.E = { +module.exports = { 'name': 'e', 'category': 'Constants', 'syntax': [ diff --git a/src/docs/constants/false.js b/src/docs/constants/false.js index 851192b3c..851084e6e 100644 --- a/src/docs/constants/false.js +++ b/src/docs/constants/false.js @@ -1,4 +1,4 @@ -math.docs['false'] = { +module.exports = { 'name': 'false', 'category': 'Constants', 'syntax': [ diff --git a/src/docs/constants/i.js b/src/docs/constants/i.js index 3a2bf396e..ae340203a 100644 --- a/src/docs/constants/i.js +++ b/src/docs/constants/i.js @@ -1,4 +1,4 @@ -math.docs.i = { +module.exports = { 'name': 'i', 'category': 'Constants', 'syntax': [ diff --git a/src/docs/constants/pi.js b/src/docs/constants/pi.js index be6016c0e..ed7ea151d 100644 --- a/src/docs/constants/pi.js +++ b/src/docs/constants/pi.js @@ -1,4 +1,4 @@ -math.docs.pi = math.docs.PI = { +module.exports = { 'name': 'pi', 'category': 'Constants', 'syntax': [ diff --git a/src/docs/constants/tau.js b/src/docs/constants/tau.js index 79037ccd7..76e3f254b 100644 --- a/src/docs/constants/tau.js +++ b/src/docs/constants/tau.js @@ -1,4 +1,4 @@ -math.docs.tau = { +module.exports = { 'name': 'tau', 'category': 'Constants', 'syntax': [ diff --git a/src/docs/constants/true.js b/src/docs/constants/true.js index 76645e9e4..fce262c3a 100644 --- a/src/docs/constants/true.js +++ b/src/docs/constants/true.js @@ -1,4 +1,4 @@ -math.docs['true'] = { +module.exports = { 'name': 'true', 'category': 'Constants', 'syntax': [ diff --git a/src/docs/function/arithmetic/abs.js b/src/docs/function/arithmetic/abs.js index bdba0447f..4b5bf329b 100644 --- a/src/docs/function/arithmetic/abs.js +++ b/src/docs/function/arithmetic/abs.js @@ -1,4 +1,4 @@ -math.docs.abs = { +module.exports = { 'name': 'abs', 'category': 'Arithmetic', 'syntax': [ diff --git a/src/docs/function/arithmetic/add.js b/src/docs/function/arithmetic/add.js index 37c77ee38..0c4193c55 100644 --- a/src/docs/function/arithmetic/add.js +++ b/src/docs/function/arithmetic/add.js @@ -1,4 +1,4 @@ -math.docs.add = { +module.exports = { 'name': 'add', 'category': 'Operators', 'syntax': [ diff --git a/src/docs/function/arithmetic/ceil.js b/src/docs/function/arithmetic/ceil.js index bab05975f..1395437a0 100644 --- a/src/docs/function/arithmetic/ceil.js +++ b/src/docs/function/arithmetic/ceil.js @@ -1,4 +1,4 @@ -math.docs.ceil = { +module.exports = { 'name': 'ceil', 'category': 'Arithmetic', 'syntax': [ diff --git a/src/docs/function/arithmetic/cube.js b/src/docs/function/arithmetic/cube.js index 2d1b3c57b..21c586678 100644 --- a/src/docs/function/arithmetic/cube.js +++ b/src/docs/function/arithmetic/cube.js @@ -1,4 +1,4 @@ -math.docs.cube = { +module.exports = { 'name': 'cube', 'category': 'Arithmetic', 'syntax': [ diff --git a/src/docs/function/arithmetic/divide.js b/src/docs/function/arithmetic/divide.js index 60a64a601..fbc51a9f6 100644 --- a/src/docs/function/arithmetic/divide.js +++ b/src/docs/function/arithmetic/divide.js @@ -1,4 +1,4 @@ -math.docs.divide = { +module.exports = { 'name': 'divide', 'category': 'Operators', 'syntax': [ diff --git a/src/docs/function/arithmetic/edivide.js b/src/docs/function/arithmetic/edivide.js index 369137772..40c503d8d 100644 --- a/src/docs/function/arithmetic/edivide.js +++ b/src/docs/function/arithmetic/edivide.js @@ -1,4 +1,4 @@ -math.docs.edivide = { +module.exports = { 'name': 'edivide', 'category': 'Operators', 'syntax': [ diff --git a/src/docs/function/arithmetic/emultiply.js b/src/docs/function/arithmetic/emultiply.js index de895e504..909026da0 100644 --- a/src/docs/function/arithmetic/emultiply.js +++ b/src/docs/function/arithmetic/emultiply.js @@ -1,4 +1,4 @@ -math.docs.emultiply = { +module.exports = { 'name': 'emultiply', 'category': 'Operators', 'syntax': [ diff --git a/src/docs/function/arithmetic/epow.js b/src/docs/function/arithmetic/epow.js index 3563b5ec9..367c0f11d 100644 --- a/src/docs/function/arithmetic/epow.js +++ b/src/docs/function/arithmetic/epow.js @@ -1,4 +1,4 @@ -math.docs.epow = { +module.exports = { 'name': 'epow', 'category': 'Operators', 'syntax': [ diff --git a/src/docs/function/arithmetic/equal.js b/src/docs/function/arithmetic/equal.js index a12bee411..e1b1eca27 100644 --- a/src/docs/function/arithmetic/equal.js +++ b/src/docs/function/arithmetic/equal.js @@ -1,4 +1,4 @@ -math.docs.equal = { +module.exports = { 'name': 'equal', 'category': 'Operators', 'syntax': [ diff --git a/src/docs/function/arithmetic/exp.js b/src/docs/function/arithmetic/exp.js index 7b9f5d748..e3afaafb1 100644 --- a/src/docs/function/arithmetic/exp.js +++ b/src/docs/function/arithmetic/exp.js @@ -1,4 +1,4 @@ -math.docs.exp = { +module.exports = { 'name': 'exp', 'category': 'Arithmetic', 'syntax': [ diff --git a/src/docs/function/arithmetic/fix.js b/src/docs/function/arithmetic/fix.js index 51297d99d..94f6b762a 100644 --- a/src/docs/function/arithmetic/fix.js +++ b/src/docs/function/arithmetic/fix.js @@ -1,4 +1,4 @@ -math.docs.fix = { +module.exports = { 'name': 'fix', 'category': 'Arithmetic', 'syntax': [ diff --git a/src/docs/function/arithmetic/floor.js b/src/docs/function/arithmetic/floor.js index 64e80e4ea..2075fd3ee 100644 --- a/src/docs/function/arithmetic/floor.js +++ b/src/docs/function/arithmetic/floor.js @@ -1,4 +1,4 @@ -math.docs.floor = { +module.exports = { 'name': 'floor', 'category': 'Arithmetic', 'syntax': [ diff --git a/src/docs/function/arithmetic/gcd.js b/src/docs/function/arithmetic/gcd.js index 5fa776795..160ceb138 100644 --- a/src/docs/function/arithmetic/gcd.js +++ b/src/docs/function/arithmetic/gcd.js @@ -1,4 +1,4 @@ -math.docs.gcd = { +module.exports = { 'name': 'gcd', 'category': 'Arithmetic', 'syntax': [ diff --git a/src/docs/function/arithmetic/larger.js b/src/docs/function/arithmetic/larger.js index 559e60024..c7506d4f9 100644 --- a/src/docs/function/arithmetic/larger.js +++ b/src/docs/function/arithmetic/larger.js @@ -1,4 +1,4 @@ -math.docs.larger = { +module.exports = { 'name': 'larger', 'category': 'Operators', 'syntax': [ diff --git a/src/docs/function/arithmetic/largereq.js b/src/docs/function/arithmetic/largereq.js index 1e1f8221f..3f6725b16 100644 --- a/src/docs/function/arithmetic/largereq.js +++ b/src/docs/function/arithmetic/largereq.js @@ -1,4 +1,4 @@ -math.docs.largereq = { +module.exports = { 'name': 'largereq', 'category': 'Operators', 'syntax': [ diff --git a/src/docs/function/arithmetic/lcm.js b/src/docs/function/arithmetic/lcm.js index abc72e345..c06bb0da5 100644 --- a/src/docs/function/arithmetic/lcm.js +++ b/src/docs/function/arithmetic/lcm.js @@ -1,4 +1,4 @@ -math.docs.lcm = { +module.exports = { 'name': 'lcm', 'category': 'Arithmetic', 'syntax': [ diff --git a/src/docs/function/arithmetic/log.js b/src/docs/function/arithmetic/log.js index 0f455d30f..1117d63fa 100644 --- a/src/docs/function/arithmetic/log.js +++ b/src/docs/function/arithmetic/log.js @@ -1,4 +1,4 @@ -math.docs.log = { +module.exports = { 'name': 'log', 'category': 'Arithmetic', 'syntax': [ diff --git a/src/docs/function/arithmetic/log10.js b/src/docs/function/arithmetic/log10.js index 367e487d2..4c1035875 100644 --- a/src/docs/function/arithmetic/log10.js +++ b/src/docs/function/arithmetic/log10.js @@ -1,4 +1,4 @@ -math.docs.log10 = { +module.exports = { 'name': 'log10', 'category': 'Arithmetic', 'syntax': [ diff --git a/src/docs/function/arithmetic/mod.js b/src/docs/function/arithmetic/mod.js index f1625eb9e..8b96d915f 100644 --- a/src/docs/function/arithmetic/mod.js +++ b/src/docs/function/arithmetic/mod.js @@ -1,4 +1,4 @@ -math.docs.mod = { +module.exports = { 'name': 'mod', 'category': 'Operators', 'syntax': [ diff --git a/src/docs/function/arithmetic/multiply.js b/src/docs/function/arithmetic/multiply.js index b57e15984..c808d35e6 100644 --- a/src/docs/function/arithmetic/multiply.js +++ b/src/docs/function/arithmetic/multiply.js @@ -1,4 +1,4 @@ -math.docs.multiply = { +module.exports = { 'name': 'multiply', 'category': 'Operators', 'syntax': [ diff --git a/src/docs/function/arithmetic/pow.js b/src/docs/function/arithmetic/pow.js index ea72c2224..87fda66b7 100644 --- a/src/docs/function/arithmetic/pow.js +++ b/src/docs/function/arithmetic/pow.js @@ -1,4 +1,4 @@ -math.docs.pow = { +module.exports = { 'name': 'pow', 'category': 'Operators', 'syntax': [ diff --git a/src/docs/function/arithmetic/round.js b/src/docs/function/arithmetic/round.js index b20e055c6..8dd193f0b 100644 --- a/src/docs/function/arithmetic/round.js +++ b/src/docs/function/arithmetic/round.js @@ -1,4 +1,4 @@ -math.docs.round = { +module.exports = { 'name': 'round', 'category': 'Arithmetic', 'syntax': [ diff --git a/src/docs/function/arithmetic/sign.js b/src/docs/function/arithmetic/sign.js index 4d4057315..432196951 100644 --- a/src/docs/function/arithmetic/sign.js +++ b/src/docs/function/arithmetic/sign.js @@ -1,4 +1,4 @@ -math.docs.sign = { +module.exports = { 'name': 'sign', 'category': 'Arithmetic', 'syntax': [ diff --git a/src/docs/function/arithmetic/smaller.js b/src/docs/function/arithmetic/smaller.js index aa56c7550..e6f7118de 100644 --- a/src/docs/function/arithmetic/smaller.js +++ b/src/docs/function/arithmetic/smaller.js @@ -1,4 +1,4 @@ -math.docs.smaller = { +module.exports = { 'name': 'smaller', 'category': 'Operators', 'syntax': [ diff --git a/src/docs/function/arithmetic/smallereq.js b/src/docs/function/arithmetic/smallereq.js index 0e4aa27d2..f52a1f5be 100644 --- a/src/docs/function/arithmetic/smallereq.js +++ b/src/docs/function/arithmetic/smallereq.js @@ -1,4 +1,4 @@ -math.docs.smallereq = { +module.exports = { 'name': 'smallereq', 'category': 'Operators', 'syntax': [ diff --git a/src/docs/function/arithmetic/sqrt.js b/src/docs/function/arithmetic/sqrt.js index 849de7132..d2d6d1cea 100644 --- a/src/docs/function/arithmetic/sqrt.js +++ b/src/docs/function/arithmetic/sqrt.js @@ -1,4 +1,4 @@ -math.docs.sqrt = { +module.exports = { 'name': 'sqrt', 'category': 'Arithmetic', 'syntax': [ diff --git a/src/docs/function/arithmetic/square.js b/src/docs/function/arithmetic/square.js index 0bd1e62b6..99ccae2fc 100644 --- a/src/docs/function/arithmetic/square.js +++ b/src/docs/function/arithmetic/square.js @@ -1,4 +1,4 @@ -math.docs.square = { +module.exports = { 'name': 'square', 'category': 'Arithmetic', 'syntax': [ diff --git a/src/docs/function/arithmetic/subtract.js b/src/docs/function/arithmetic/subtract.js index fd7599dba..2ffefba6b 100644 --- a/src/docs/function/arithmetic/subtract.js +++ b/src/docs/function/arithmetic/subtract.js @@ -1,4 +1,4 @@ -math.docs.subtract = { +module.exports = { 'name': 'subtract', 'category': 'Operators', 'syntax': [ diff --git a/src/docs/function/arithmetic/unary.js b/src/docs/function/arithmetic/unary.js index f998f7f81..964b3acb6 100644 --- a/src/docs/function/arithmetic/unary.js +++ b/src/docs/function/arithmetic/unary.js @@ -1,4 +1,4 @@ -math.docs.unary = { +module.exports = { 'name': 'unary', 'category': 'Operators', 'syntax': [ diff --git a/src/docs/function/arithmetic/unequal.js b/src/docs/function/arithmetic/unequal.js index 9aab11266..2311c5aa6 100644 --- a/src/docs/function/arithmetic/unequal.js +++ b/src/docs/function/arithmetic/unequal.js @@ -1,4 +1,4 @@ -math.docs.unequal = { +module.exports = { 'name': 'unequal', 'category': 'Operators', 'syntax': [ diff --git a/src/docs/function/arithmetic/xgcd.js b/src/docs/function/arithmetic/xgcd.js index 3f11cedc1..c7232ac22 100644 --- a/src/docs/function/arithmetic/xgcd.js +++ b/src/docs/function/arithmetic/xgcd.js @@ -1,4 +1,4 @@ -math.docs.xgcd = { +module.exports = { 'name': 'xgcd', 'category': 'Arithmetic', 'syntax': [ diff --git a/src/docs/function/complex/arg.js b/src/docs/function/complex/arg.js index 2daee96a5..6f14b1fb8 100644 --- a/src/docs/function/complex/arg.js +++ b/src/docs/function/complex/arg.js @@ -1,4 +1,4 @@ -math.docs.arg = { +module.exports = { 'name': 'arg', 'category': 'Complex', 'syntax': [ diff --git a/src/docs/function/complex/conj.js b/src/docs/function/complex/conj.js index d8240d364..b57b9813d 100644 --- a/src/docs/function/complex/conj.js +++ b/src/docs/function/complex/conj.js @@ -1,4 +1,4 @@ -math.docs.conj = { +module.exports = { 'name': 'conj', 'category': 'Complex', 'syntax': [ diff --git a/src/docs/function/complex/im.js b/src/docs/function/complex/im.js index 7316b987c..7608d6575 100644 --- a/src/docs/function/complex/im.js +++ b/src/docs/function/complex/im.js @@ -1,4 +1,4 @@ -math.docs.im = { +module.exports = { 'name': 'im', 'category': 'Complex', 'syntax': [ diff --git a/src/docs/function/complex/re.js b/src/docs/function/complex/re.js index b14defbbf..6fa53efeb 100644 --- a/src/docs/function/complex/re.js +++ b/src/docs/function/complex/re.js @@ -1,4 +1,4 @@ -math.docs.re = { +module.exports = { 'name': 're', 'category': 'Complex', 'syntax': [ diff --git a/src/docs/function/construction/boolean.js b/src/docs/function/construction/boolean.js index 1e3dcf569..5d830a2b0 100644 --- a/src/docs/function/construction/boolean.js +++ b/src/docs/function/construction/boolean.js @@ -1,4 +1,4 @@ -math.docs['boolean'] = { +module.exports = { 'name': 'boolean', 'category': 'Type', 'syntax': [ diff --git a/src/docs/function/construction/complex.js b/src/docs/function/construction/complex.js index ba93be9f8..76882d6f9 100644 --- a/src/docs/function/construction/complex.js +++ b/src/docs/function/construction/complex.js @@ -1,4 +1,4 @@ -math.docs.complex = { +module.exports = { 'name': 'complex', 'category': 'Type', 'syntax': [ diff --git a/src/docs/function/construction/matrix.js b/src/docs/function/construction/matrix.js index f17b66e6f..513b11e9e 100644 --- a/src/docs/function/construction/matrix.js +++ b/src/docs/function/construction/matrix.js @@ -1,4 +1,4 @@ -math.docs.matrix = { +module.exports = { 'name': 'matrix', 'category': 'Type', 'syntax': [ diff --git a/src/docs/function/construction/number.js b/src/docs/function/construction/number.js index 18543fb40..72cf9a97a 100644 --- a/src/docs/function/construction/number.js +++ b/src/docs/function/construction/number.js @@ -1,4 +1,4 @@ -math.docs.number = { +module.exports = { 'name': 'number', 'category': 'Type', 'syntax': [ diff --git a/src/docs/function/construction/range.js b/src/docs/function/construction/range.js index 4f6449be7..55dfa5591 100644 --- a/src/docs/function/construction/range.js +++ b/src/docs/function/construction/range.js @@ -1,4 +1,4 @@ -math.docs.range = { +module.exports = { 'name': 'range', 'category': 'Type', 'syntax': [ diff --git a/src/docs/function/construction/string.js b/src/docs/function/construction/string.js index c0f202bb3..ceb6b42dd 100644 --- a/src/docs/function/construction/string.js +++ b/src/docs/function/construction/string.js @@ -1,4 +1,4 @@ -math.docs.string = { +module.exports = { 'name': 'string', 'category': 'Type', 'syntax': [ diff --git a/src/docs/function/construction/unit.js b/src/docs/function/construction/unit.js index 4531b9504..5917182c9 100644 --- a/src/docs/function/construction/unit.js +++ b/src/docs/function/construction/unit.js @@ -1,4 +1,4 @@ -math.docs.unit = { +module.exports = { 'name': 'unit', 'category': 'Type', 'syntax': [ diff --git a/src/docs/function/matrix/concat.js b/src/docs/function/matrix/concat.js index 4e5834575..270fadf91 100644 --- a/src/docs/function/matrix/concat.js +++ b/src/docs/function/matrix/concat.js @@ -1,4 +1,4 @@ -math.docs.concat = { +module.exports = { 'name': 'concat', 'category': 'Matrix', 'syntax': [ diff --git a/src/docs/function/matrix/det.js b/src/docs/function/matrix/det.js index 3455ec0d9..aafb283e2 100644 --- a/src/docs/function/matrix/det.js +++ b/src/docs/function/matrix/det.js @@ -1,4 +1,4 @@ -math.docs.det = { +module.exports = { 'name': 'det', 'category': 'Matrix', 'syntax': [ diff --git a/src/docs/function/matrix/diag.js b/src/docs/function/matrix/diag.js index 0a62f16cf..473d87530 100644 --- a/src/docs/function/matrix/diag.js +++ b/src/docs/function/matrix/diag.js @@ -1,4 +1,4 @@ -math.docs.diag = { +module.exports = { 'name': 'diag', 'category': 'Matrix', 'syntax': [ diff --git a/src/docs/function/matrix/eye.js b/src/docs/function/matrix/eye.js index d5a23cb22..5163b840d 100644 --- a/src/docs/function/matrix/eye.js +++ b/src/docs/function/matrix/eye.js @@ -1,4 +1,4 @@ -math.docs.eye = { +module.exports = { 'name': 'eye', 'category': 'Matrix', 'syntax': [ diff --git a/src/docs/function/matrix/inv.js b/src/docs/function/matrix/inv.js index 8debbaefa..2afe90f5f 100644 --- a/src/docs/function/matrix/inv.js +++ b/src/docs/function/matrix/inv.js @@ -1,4 +1,4 @@ -math.docs.inv = { +module.exports = { 'name': 'inv', 'category': 'Matrix', 'syntax': [ diff --git a/src/docs/function/matrix/ones.js b/src/docs/function/matrix/ones.js index 5f0127369..c2d7f31b1 100644 --- a/src/docs/function/matrix/ones.js +++ b/src/docs/function/matrix/ones.js @@ -1,4 +1,4 @@ -math.docs.ones = { +module.exports = { 'name': 'ones', 'category': 'Matrix', 'syntax': [ diff --git a/src/docs/function/matrix/size.js b/src/docs/function/matrix/size.js index 8c96a085a..b41856a74 100644 --- a/src/docs/function/matrix/size.js +++ b/src/docs/function/matrix/size.js @@ -1,4 +1,4 @@ -math.docs.size = { +module.exports = { 'name': 'size', 'category': 'Matrix', 'syntax': [ diff --git a/src/docs/function/matrix/squeeze.js b/src/docs/function/matrix/squeeze.js index 3a5167222..adfdd48f6 100644 --- a/src/docs/function/matrix/squeeze.js +++ b/src/docs/function/matrix/squeeze.js @@ -1,4 +1,4 @@ -math.docs.squeeze = { +module.exports = { 'name': 'squeeze', 'category': 'Matrix', 'syntax': [ diff --git a/src/docs/function/matrix/subset.js b/src/docs/function/matrix/subset.js index 186d929f5..a99f11e69 100644 --- a/src/docs/function/matrix/subset.js +++ b/src/docs/function/matrix/subset.js @@ -1,4 +1,4 @@ -math.docs.subset = { +module.exports = { 'name': 'subset', 'category': 'Matrix', 'syntax': [ diff --git a/src/docs/function/matrix/transpose.js b/src/docs/function/matrix/transpose.js index e80ae1ad3..f0fbca22e 100644 --- a/src/docs/function/matrix/transpose.js +++ b/src/docs/function/matrix/transpose.js @@ -1,4 +1,4 @@ -math.docs.transpose = { +module.exports = { 'name': 'transpose', 'category': 'Matrix', 'syntax': [ diff --git a/src/docs/function/matrix/zeros.js b/src/docs/function/matrix/zeros.js index b94fecc1d..4a4506bbc 100644 --- a/src/docs/function/matrix/zeros.js +++ b/src/docs/function/matrix/zeros.js @@ -1,4 +1,4 @@ -math.docs.zeros = { +module.exports = { 'name': 'zeros', 'category': 'Matrix', 'syntax': [ diff --git a/src/docs/function/probability/factorial.js b/src/docs/function/probability/factorial.js index 674c1de40..dc146cda0 100644 --- a/src/docs/function/probability/factorial.js +++ b/src/docs/function/probability/factorial.js @@ -1,4 +1,4 @@ -math.docs.factorial = { +module.exports = { 'name': 'factorial', 'category': 'Probability', 'syntax': [ diff --git a/src/docs/function/probability/random.js b/src/docs/function/probability/random.js index e931b4ffe..9a04f643c 100644 --- a/src/docs/function/probability/random.js +++ b/src/docs/function/probability/random.js @@ -1,4 +1,4 @@ -math.docs.random = { +module.exports = { 'name': 'random', 'category': 'Probability', 'syntax': [ @@ -11,17 +11,3 @@ math.docs.random = { ], 'seealso': [] }; - -math.docs.randInt = { - 'name': 'randInt', - 'category': 'Probability', - 'syntax': [ - 'randInt()' - ], - 'description': - 'Return a random number between 0 and 1.', - 'examples': [ - 'randInt()' - ], - 'seealso': [] -}; \ No newline at end of file diff --git a/src/docs/function/probability/randomInt.js b/src/docs/function/probability/randomInt.js new file mode 100644 index 000000000..f0da378e8 --- /dev/null +++ b/src/docs/function/probability/randomInt.js @@ -0,0 +1,13 @@ +module.exports = { + 'name': 'randInt', + 'category': 'Probability', + 'syntax': [ + 'randInt()' + ], + 'description': + 'Return a random number between 0 and 1.', + 'examples': [ + 'randInt()' + ], + 'seealso': [] +}; \ No newline at end of file diff --git a/src/docs/function/statistics/max.js b/src/docs/function/statistics/max.js index d4fd6a933..5941a0e72 100644 --- a/src/docs/function/statistics/max.js +++ b/src/docs/function/statistics/max.js @@ -1,4 +1,4 @@ -math.docs.max = { +module.exports = { 'name': 'max', 'category': 'Statistics', 'syntax': [ diff --git a/src/docs/function/statistics/min.js b/src/docs/function/statistics/min.js index f30c17b72..adfb7f487 100644 --- a/src/docs/function/statistics/min.js +++ b/src/docs/function/statistics/min.js @@ -1,4 +1,4 @@ -math.docs.min = { +module.exports = { 'name': 'min', 'category': 'Statistics', 'syntax': [ diff --git a/src/docs/function/trigonometry/acos.js b/src/docs/function/trigonometry/acos.js index 042d5cd17..78ffe9da6 100644 --- a/src/docs/function/trigonometry/acos.js +++ b/src/docs/function/trigonometry/acos.js @@ -1,4 +1,4 @@ -math.docs.acos = { +module.exports = { 'name': 'acos', 'category': 'Trigonometry', 'syntax': [ diff --git a/src/docs/function/trigonometry/asin.js b/src/docs/function/trigonometry/asin.js index 78a2f9bae..6e53189e0 100644 --- a/src/docs/function/trigonometry/asin.js +++ b/src/docs/function/trigonometry/asin.js @@ -1,4 +1,4 @@ -math.docs.asin = { +module.exports = { 'name': 'asin', 'category': 'Trigonometry', 'syntax': [ diff --git a/src/docs/function/trigonometry/atan.js b/src/docs/function/trigonometry/atan.js index c41c1c22a..4780256da 100644 --- a/src/docs/function/trigonometry/atan.js +++ b/src/docs/function/trigonometry/atan.js @@ -1,4 +1,4 @@ -math.docs.atan = { +module.exports = { 'name': 'atan', 'category': 'Trigonometry', 'syntax': [ diff --git a/src/docs/function/trigonometry/atan2.js b/src/docs/function/trigonometry/atan2.js index 9356b8aad..da6dc5a29 100644 --- a/src/docs/function/trigonometry/atan2.js +++ b/src/docs/function/trigonometry/atan2.js @@ -1,4 +1,4 @@ -math.docs.atan2 = { +module.exports = { 'name': 'atan2', 'category': 'Trigonometry', 'syntax': [ diff --git a/src/docs/function/trigonometry/cos.js b/src/docs/function/trigonometry/cos.js index 8d57f5a8f..412df2baf 100644 --- a/src/docs/function/trigonometry/cos.js +++ b/src/docs/function/trigonometry/cos.js @@ -1,4 +1,4 @@ -math.docs.cos = { +module.exports = { 'name': 'cos', 'category': 'Trigonometry', 'syntax': [ diff --git a/src/docs/function/trigonometry/cot.js b/src/docs/function/trigonometry/cot.js index c461fad5c..1d7fa12b8 100644 --- a/src/docs/function/trigonometry/cot.js +++ b/src/docs/function/trigonometry/cot.js @@ -1,4 +1,4 @@ -math.docs.cot = { +module.exports = { 'name': 'cot', 'category': 'Trigonometry', 'syntax': [ diff --git a/src/docs/function/trigonometry/csc.js b/src/docs/function/trigonometry/csc.js index cbb4bd3f4..bfe7d6fde 100644 --- a/src/docs/function/trigonometry/csc.js +++ b/src/docs/function/trigonometry/csc.js @@ -1,4 +1,4 @@ -math.docs.csc = { +module.exports = { 'name': 'csc', 'category': 'Trigonometry', 'syntax': [ diff --git a/src/docs/function/trigonometry/sec.js b/src/docs/function/trigonometry/sec.js index 7e756d14c..9b931aa6a 100644 --- a/src/docs/function/trigonometry/sec.js +++ b/src/docs/function/trigonometry/sec.js @@ -1,4 +1,4 @@ -math.docs.sec = { +module.exports = { 'name': 'sec', 'category': 'Trigonometry', 'syntax': [ diff --git a/src/docs/function/trigonometry/sin.js b/src/docs/function/trigonometry/sin.js index 40156a41f..6d6f7f7a8 100644 --- a/src/docs/function/trigonometry/sin.js +++ b/src/docs/function/trigonometry/sin.js @@ -1,4 +1,4 @@ -math.docs.sin = { +module.exports = { 'name': 'sin', 'category': 'Trigonometry', 'syntax': [ diff --git a/src/docs/function/trigonometry/tan.js b/src/docs/function/trigonometry/tan.js index 065767439..14c281982 100644 --- a/src/docs/function/trigonometry/tan.js +++ b/src/docs/function/trigonometry/tan.js @@ -1,4 +1,4 @@ -math.docs.tan = { +module.exports = { 'name': 'tan', 'category': 'Trigonometry', 'syntax': [ diff --git a/src/docs/function/units/in.js b/src/docs/function/units/in.js index 3098825bf..572c7f350 100644 --- a/src/docs/function/units/in.js +++ b/src/docs/function/units/in.js @@ -1,4 +1,4 @@ -math.docs['in'] = { +module.exports = { 'name': 'in', 'category': 'Units', 'syntax': [ diff --git a/src/docs/function/utils/clone.js b/src/docs/function/utils/clone.js index 32c177fbd..18ca109c3 100644 --- a/src/docs/function/utils/clone.js +++ b/src/docs/function/utils/clone.js @@ -1,4 +1,4 @@ -math.docs.clone = { +module.exports = { 'name': 'clone', 'category': 'Utils', 'syntax': [ diff --git a/src/docs/function/utils/eval.js b/src/docs/function/utils/eval.js index aba89b703..0eba6892e 100644 --- a/src/docs/function/utils/eval.js +++ b/src/docs/function/utils/eval.js @@ -1,4 +1,4 @@ -math.docs['eval'] = { +module.exports = { 'name': 'eval', 'category': 'Utils', 'syntax': [ diff --git a/src/docs/function/utils/format.js b/src/docs/function/utils/format.js index 983302150..98ad21f5f 100644 --- a/src/docs/function/utils/format.js +++ b/src/docs/function/utils/format.js @@ -1,4 +1,4 @@ -math.docs.format = { +module.exports = { 'name': 'format', 'category': 'Utils', 'syntax': [ diff --git a/src/docs/function/utils/help.js b/src/docs/function/utils/help.js index 128247be2..20a011a0b 100644 --- a/src/docs/function/utils/help.js +++ b/src/docs/function/utils/help.js @@ -1,4 +1,4 @@ -math.docs.help = { +module.exports = { 'name': 'help', 'category': 'Utils', 'syntax': [ diff --git a/src/docs/function/utils/import.js b/src/docs/function/utils/import.js index a161ba038..b9efc92cf 100644 --- a/src/docs/function/utils/import.js +++ b/src/docs/function/utils/import.js @@ -1,4 +1,4 @@ -math.docs['import'] = { +module.exports = { 'name': 'import', 'category': 'Utils', 'syntax': [ diff --git a/src/docs/function/utils/typeof.js b/src/docs/function/utils/typeof.js index 657a5cf87..71e329bc9 100644 --- a/src/docs/function/utils/typeof.js +++ b/src/docs/function/utils/typeof.js @@ -1,4 +1,4 @@ -math.docs['typeof'] = { +module.exports = { 'name': 'typeof', 'category': 'Utils', 'syntax': [ diff --git a/src/docs/index.js b/src/docs/index.js new file mode 100644 index 000000000..21b82313b --- /dev/null +++ b/src/docs/index.js @@ -0,0 +1,110 @@ +// constants +exports.e = require('./constants/e.js'); +exports.E = require('./constants/e.js'); +exports['false'] = require('./constants/false.js'); +exports.i = require('./constants/i.js'); +exports['Infinity'] = require('./constants/Infinity.js'); +exports.LN2 = require('./constants/LN2.js'); +exports.LN10 = require('./constants/LN10.js'); +exports.LOG2E = require('./constants/LOG2E.js'); +exports.LOG10E = require('./constants/LOG10E.js'); +exports.NaN = require('./constants/NaN.js'); +exports.pi = require('./constants/pi.js'); +exports.PI = require('./constants/pi.js'); +exports.SQRT1_2 = require('./constants/SQRT1_2.js'); +exports.SQRT2 = require('./constants/SQRT2.js'); +exports.tau = require('./constants/tau.js'); +exports['true'] = require('./constants/true.js'); + +// functions - arithmetic +exports.abs = require('./function/arithmetic/abs.js'); +exports.add = require('./function/arithmetic/add.js'); +exports.ceil = require('./function/arithmetic/ceil.js'); +exports.cube = require('./function/arithmetic/cube.js'); +exports.divide = require('./function/arithmetic/divide.js'); +exports.edivide = require('./function/arithmetic/edivide.js'); +exports.emultiply = require('./function/arithmetic/emultiply.js'); +exports.epow = require('./function/arithmetic/epow.js'); +exports.equal = require('./function/arithmetic/equal.js'); +exports.exp = require('./function/arithmetic/exp.js'); +exports.fix = require('./function/arithmetic/fix.js'); +exports.floor = require('./function/arithmetic/floor.js'); +exports.gcd = require('./function/arithmetic/gcd.js'); +exports.larger = require('./function/arithmetic/larger.js'); +exports.largereq = require('./function/arithmetic/largereq.js'); +exports.lcm = require('./function/arithmetic/lcm.js'); +exports.log = require('./function/arithmetic/log.js'); +exports.log10 = require('./function/arithmetic/log10.js'); +exports.mod = require('./function/arithmetic/mod.js'); +exports.multiply = require('./function/arithmetic/multiply.js'); +exports.pow = require('./function/arithmetic/pow.js'); +exports.round = require('./function/arithmetic/round.js'); +exports.sign = require('./function/arithmetic/sign.js'); +exports.smaller = require('./function/arithmetic/smaller.js'); +exports.smallereq = require('./function/arithmetic/smallereq.js'); +exports.sqrt = require('./function/arithmetic/sqrt.js'); +exports.square = require('./function/arithmetic/square.js'); +exports.subtract = require('./function/arithmetic/subtract.js'); +exports.unary = require('./function/arithmetic/unary.js'); +exports.unequal = require('./function/arithmetic/unequal.js'); +exports.xgcd = require('./function/arithmetic/xgcd.js'); + +// functions - complex +exports.arg = require('./function/complex/arg.js'); +exports.conj = require('./function/complex/conj.js'); +exports.re = require('./function/complex/re.js'); +exports.im = require('./function/complex/im.js'); + +// functions - construction +exports.boolean = require('./function/construction/boolean.js'); +exports.complex = require('./function/construction/complex.js'); +exports.matrix = require('./function/construction/matrix.js'); +exports.number = require('./function/construction/number.js'); +exports.range = require('./function/construction/range.js'); +exports.string = require('./function/construction/string.js'); +exports.unit = require('./function/construction/unit.js'); + +// functions - matrix +exports.concat = require('./function/matrix/concat.js'); +exports.det = require('./function/matrix/det.js'); +exports.diag = require('./function/matrix/diag.js'); +exports.eye = require('./function/matrix/eye.js'); +exports.inv = require('./function/matrix/inv.js'); +exports.ones = require('./function/matrix/ones.js'); +exports.size = require('./function/matrix/size.js'); +exports.squeeze = require('./function/matrix/squeeze.js'); +exports.subset = require('./function/matrix/subset.js'); +exports.transpose = require('./function/matrix/transpose.js'); +exports.zeros = require('./function/matrix/zeros.js'); + +// functions - probability +exports.factorial = require('./function/probability/factorial.js'); +exports.random = require('./function/probability/random.js'); +exports.randomInt = require('./function/probability/randomInt.js'); + +// functions - statistics +exports.min = require('./function/statistics/min.js'); +exports.max = require('./function/statistics/max.js'); + +// functions - trigonometry +exports.acos = require('./function/trigonometry/acos.js'); +exports.asin = require('./function/trigonometry/asin.js'); +exports.atan = require('./function/trigonometry/atan.js'); +exports.atan2 = require('./function/trigonometry/atan2.js'); +exports.cos = require('./function/trigonometry/cos.js'); +exports.cot = require('./function/trigonometry/cot.js'); +exports.csc = require('./function/trigonometry/csc.js'); +exports.sec = require('./function/trigonometry/sec.js'); +exports.sin = require('./function/trigonometry/sin.js'); +exports.tan = require('./function/trigonometry/tan.js'); + +// functions - units +exports['in'] = require('./function/units/in.js'); + +// functions - utils +exports.clone = require('./function/utils/clone.js'); +exports['eval'] = require('./function/utils/eval.js'); +exports.format = require('./function/utils/format.js'); +exports.help = require('./function/utils/help.js'); +exports['import'] = require('./function/utils/import.js'); +exports['typeof'] = require('./function/utils/typeof.js'); diff --git a/src/exports.js b/src/exports.js index 926d13856..3e5226c69 100644 --- a/src/exports.js +++ b/src/exports.js @@ -11,7 +11,7 @@ if (typeof exports !== 'undefined') { /** * AMD module exports */ -if (typeof(require) != 'undefined' && typeof(define) != 'undefined') { +if (typeof(require) !== 'undefined' && typeof(define) !== 'undefined') { define(function () { return math; }); @@ -20,9 +20,9 @@ if (typeof(require) != 'undefined' && typeof(define) != 'undefined') { /** * Browser exports */ -if (typeof(window) != 'undefined') { +if (typeof(window) !== 'undefined') { if (window['math']) { - util.deepExtend(window['math'], math); + object.deepExtend(window['math'], math); } else { window['math'] = math; diff --git a/src/expr/Parser.js b/src/expr/Parser.js index 2d9032ebb..ba29c2dfb 100644 --- a/src/expr/Parser.js +++ b/src/expr/Parser.js @@ -1,6 +1,8 @@ +var math = require('../math.js'), + Scope = require('./Scope.js'); /** - * @constructor math.expr.Parser + * @constructor Parser * Parser contains methods to evaluate or parse expressions, and has a number * of convenience methods to get, set, and remove variables from memory. Parser * keeps a scope containing variables in memory, which is used for all @@ -19,7 +21,7 @@ * var result = node.eval(); // evaluate a parsed node * * Example usage: - * var parser = new math.expr.Parser(); + * var parser = new Parser(); * // Note: there is a convenience method which can be used instead: * // var parser = new math.parser(); * @@ -49,14 +51,14 @@ * // clear defined functions and variables * parser.clear(); */ -math.expr.Parser = function Parser() { - if (!(this instanceof math.expr.Parser)) { +function Parser() { + if (!(this instanceof Parser)) { throw new SyntaxError( 'Parser constructor must be called with the new operator'); } - this.scope = new math.expr.Scope(); -}; + this.scope = new Scope(); +} /** * Parse an expression end return the parsed function node. @@ -65,7 +67,7 @@ math.expr.Parser = function Parser() { * @return {Node} node * @throws {Error} */ -math.expr.Parser.prototype.parse = function (expr) { +Parser.prototype.parse = function (expr) { return math.parse(expr, this.scope); }; @@ -75,7 +77,7 @@ math.expr.Parser.prototype.parse = function (expr) { * @return {*} result The result, or undefined when the expression was empty * @throws {Error} */ -math.expr.Parser.prototype.eval = function (expr) { +Parser.prototype.eval = function (expr) { var node = math.parse(expr, this.scope); return node.eval(); }; @@ -86,7 +88,7 @@ math.expr.Parser.prototype.eval = function (expr) { * @param {String} name * @return {* | undefined} value */ -math.expr.Parser.prototype.get = function (name) { +Parser.prototype.get = function (name) { return this.scope.get(name); }; @@ -95,7 +97,7 @@ math.expr.Parser.prototype.get = function (name) { * @param {String} name * @param {* | undefined} value */ -math.expr.Parser.prototype.set = function (name, value) { +Parser.prototype.set = function (name, value) { this.scope.set(name, value); }; @@ -103,13 +105,15 @@ math.expr.Parser.prototype.set = function (name, value) { * Remove a variable from the parsers scope * @param {String} name */ -math.expr.Parser.prototype.remove = function (name) { +Parser.prototype.remove = function (name) { this.scope.remove(name); }; /** * Clear the scope with variables and functions */ -math.expr.Parser.prototype.clear = function () { +Parser.prototype.clear = function () { this.scope.clear(); }; + +module.exports = Parser; diff --git a/src/expr/Scope.js b/src/expr/Scope.js index 26e255fd1..601ea8470 100644 --- a/src/expr/Scope.js +++ b/src/expr/Scope.js @@ -1,30 +1,32 @@ +var math = require('../math.js'), + Unit = require('../type/Unit.js'); /** * Scope * A scope stores values of symbols: variables and functions. * * Syntax: - * var scope = new math.expr.Scope(); - * var scope = new math.expr.Scope(parentScope); - * var scope = new math.expr.Scope(symbols); - * var scope = new math.expr.Scope(parentScope, symbols); + * var scope = new Scope(); + * var scope = new Scope(parentScope); + * var scope = new Scope(symbols); + * var scope = new Scope(parentScope, symbols); * * Where: - * {math.expr.Scope} parentScope Scope will be linked to a parent scope, + * {Scope} parentScope Scope will be linked to a parent scope, * which is traversed when resolving * symbols. * {Object} symbols A custom object that will be used to * resolve and store variables. * - * @constructor math.expr.Scope + * @constructor Scope * @param {...} [args] */ -math.expr.Scope = function Scope(args) { - /** @type {math.expr.Scope} */ +function Scope(args) { + /** @type {Scope} */ this.parentScope = null; // TODO: rename parentScope to previousScope, add a nextScope, change Scope to a linked list node - /** @type {math.expr.Scope[]} */ + /** @type {Scope[]} */ this.subScopes = null; // TODO: rename subScopes to childScopes (or childNodes?) @@ -38,7 +40,7 @@ math.expr.Scope = function Scope(args) { // read first argument (can be parentScope or symbols map) if (arguments.length > 0) { var arg0 = arguments[0]; - if (arg0 instanceof math.expr.Scope) { + if (arg0 instanceof Scope) { this.parentScope = arg0; } else if (arg0 instanceof Object) { @@ -53,16 +55,16 @@ math.expr.Scope = function Scope(args) { this.symbols = arg1; } } -}; +} -math.expr.Scope.prototype = { +Scope.prototype = { /** * Create a sub scope * The variables in a sub scope are not accessible from the parent scope - * @return {math.expr.Scope} subScope + * @return {Scope} subScope */ createSubScope: function () { - var subScope = new math.expr.Scope(this); + var subScope = new Scope(this); if (!this.subScopes) { this.subScopes = []; } @@ -177,3 +179,5 @@ math.expr.Scope.prototype = { this.cache = {}; } }; + +module.exports = Scope; diff --git a/src/type/Selector.js b/src/expr/Selector.js similarity index 74% rename from src/type/Selector.js rename to src/expr/Selector.js index afecb00c6..f7c406e1f 100644 --- a/src/type/Selector.js +++ b/src/expr/Selector.js @@ -1,5 +1,9 @@ +var math = require('../math.js'), + util = require('../util/index.js'), + string = util.string; + /** - * @constructor math.type.Selector + * @constructor Selector * Wrap any value in a Selector, allowing to perform chained operations on * the value. * @@ -20,21 +24,21 @@ * * @param {*} [value] */ -math.type.Selector = function Selector (value) { - if (!(this instanceof math.type.Selector)) { +function Selector (value) { + if (!(this instanceof Selector)) { throw new SyntaxError( 'Selector constructor must be called with the new operator'); } - if (value instanceof math.type.Selector) { + if (value instanceof Selector) { this.value = value.value; } else { this.value = value; } -}; +} -math.type.Selector.prototype = { +Selector.prototype = { /** * Close the selector. Returns the final value. * Does the same as method valueOf() @@ -54,7 +58,7 @@ math.type.Selector.prototype = { throw Error('Selector value is undefined'); } - return new math.type.Selector(math.subset(value, index)); + return new Selector(math.subset(value, index)); }, /** @@ -67,7 +71,7 @@ math.type.Selector.prototype = { throw Error('Selector value is undefined'); } - return new math.type.Selector(math.subset(value, index, replacement)); + return new Selector(math.subset(value, index, replacement)); }, /** @@ -84,7 +88,7 @@ math.type.Selector.prototype = { * @returns {String} */ toString: function () { - return math.format(this.value); + return string.format(this.value); } }; @@ -93,8 +97,7 @@ math.type.Selector.prototype = { * @param {String} name * @param {*} value The value or function to be proxied */ -function createSelectorProxy(name, value) { - var Selector = math.type.Selector; +function createProxy(name, value) { var slice = Array.prototype.slice; if (typeof value === 'function') { // a function @@ -108,3 +111,24 @@ function createSelectorProxy(name, value) { Selector.prototype[name] = new Selector(value); } } + +Selector.createProxy = createProxy; + +/** + * initialise the Chain prototype with all functions and constants in math + */ +Selector.init = function init () { + Selector.init = null; // delete, we are initialized + + for (var prop in math) { + if (math.hasOwnProperty(prop) && prop) { + createProxy(prop, math[prop]); + } + } +}; + +// exports +module.exports = Selector; +exports.init = Selector.init; + +util.types.addType('selector', Selector); diff --git a/src/expr/index.js b/src/expr/index.js new file mode 100644 index 000000000..eeab8e1dc --- /dev/null +++ b/src/expr/index.js @@ -0,0 +1,4 @@ +exports.node = require('./node/index.js'); +exports.Scope = require('./Scope.js'); +exports.Parser = require('./Parser.js'); +exports.Selector = require('./Selector.js'); diff --git a/src/expr/node/AssignmentNode.js b/src/expr/node/AssignmentNode.js index 9dcfac423..871fb5e79 100644 --- a/src/expr/node/AssignmentNode.js +++ b/src/expr/node/AssignmentNode.js @@ -1,10 +1,12 @@ +var Node = require('./Node.js'); + /** * @constructor AssignmentNode * Define a symbol, like "a = 3.2" * - * @param {String} name Symbol name - * @param {Node} expr The expression defining the symbol - * @param {math.expr.Scope} scope Scope to store the result + * @param {String} name Symbol name + * @param {Node} expr The expression defining the symbol + * @param {Scope} scope Scope to store the result */ function AssignmentNode(name, expr, scope) { this.name = name; @@ -14,8 +16,6 @@ function AssignmentNode(name, expr, scope) { AssignmentNode.prototype = new Node(); -math.expr.node.AssignmentNode = AssignmentNode; - /** * Evaluate the assignment * @return {*} result @@ -59,3 +59,5 @@ AssignmentNode.prototype.find = function (filter) { AssignmentNode.prototype.toString = function() { return this.name + ' = ' + this.expr.toString(); }; + +module.exports = AssignmentNode; \ No newline at end of file diff --git a/src/expr/node/BlockNode.js b/src/expr/node/BlockNode.js index 1d203d08d..bdb1ec758 100644 --- a/src/expr/node/BlockNode.js +++ b/src/expr/node/BlockNode.js @@ -1,3 +1,5 @@ +var Node = require('./Node.js'); + /** * @constructor BlockNode * Holds a set with nodes @@ -10,8 +12,6 @@ function BlockNode() { BlockNode.prototype = new Node(); -math.expr.node.BlockNode = BlockNode; - /** * Add a parameter * @param {Node} param @@ -81,3 +81,5 @@ BlockNode.prototype.toString = function() { return '[' + strings.join(',') + '\n]'; }; + +module.exports = BlockNode; diff --git a/src/expr/node/ConstantNode.js b/src/expr/node/ConstantNode.js index 8d85ae77e..e82d36580 100644 --- a/src/expr/node/ConstantNode.js +++ b/src/expr/node/ConstantNode.js @@ -1,3 +1,6 @@ +var Node = require('./Node.js'), + string = require('../../util/string.js'); + /** * @constructor ConstantNode * @param {*} value @@ -9,8 +12,6 @@ function ConstantNode(value) { ConstantNode.prototype = new Node(); -math.expr.node.ConstantNode = ConstantNode; - /** * Evaluate the constant (just return it) * @return {*} value @@ -24,5 +25,7 @@ ConstantNode.prototype.eval = function () { * @return {String} str */ ConstantNode.prototype.toString = function() { - return math.format(this.value); + return string.format(this.value); }; + +module.exports = ConstantNode; diff --git a/src/expr/node/FunctionNode.js b/src/expr/node/FunctionNode.js index e5023fe09..dad2400db 100644 --- a/src/expr/node/FunctionNode.js +++ b/src/expr/node/FunctionNode.js @@ -1,14 +1,15 @@ +var Node = require('./Node.js'), + error = require('../../util/error.js'); + /** * @constructor FunctionNode * Function assignment * - * @param {String} name Function name - * @param {String[]} variables Variable names - * @param {Node} expr The function expression - * @param {math.expr.Scope} functionScope Scope in which to write variable - * values - * @param {math.expr.Scope} scope Scope to store the resulting - * function assignment + * @param {String} name Function name + * @param {String[]} variables Variable names + * @param {Node} expr The function expression + * @param {Scope} functionScope Scope in which to write variable values + * @param {Scope} scope Scope to store the resulting function assignment */ function FunctionNode(name, variables, expr, functionScope, scope) { this.name = name; @@ -22,7 +23,7 @@ function FunctionNode(name, variables, expr, functionScope, scope) { // validate correct number of arguments if (arguments.length != num) { - throw newArgumentsError(name, arguments.length, num); + throw new error.ArgumentsError(name, arguments.length, num); } // fill in the provided arguments in the functionScope variables @@ -43,8 +44,6 @@ function FunctionNode(name, variables, expr, functionScope, scope) { FunctionNode.prototype = new Node(); -math.expr.node.FunctionNode = FunctionNode; - /** * Evaluate the function assignment * @return {function} fn @@ -84,3 +83,5 @@ FunctionNode.prototype.find = function (filter) { FunctionNode.prototype.toString = function() { return this.fn.toString(); }; + +module.exports = FunctionNode; diff --git a/src/expr/node/MatrixNode.js b/src/expr/node/MatrixNode.js index 44fe9797d..612f33d57 100644 --- a/src/expr/node/MatrixNode.js +++ b/src/expr/node/MatrixNode.js @@ -1,3 +1,10 @@ +var Node = require('./Node.js'), + object = require('../../util/object.js'), + string = require('../../util/string.js'), + collection = require('../../type/collection.js'), + Matrix = require('../../type/Matrix.js'), + Range = require('../../type/Range.js'); + /** * @constructor MatrixNode * Holds an 2-dimensional array with nodes @@ -10,143 +17,139 @@ function MatrixNode(nodes) { MatrixNode.prototype = new Node(); -math.expr.node.MatrixNode = MatrixNode; +/** + * Evaluate the array + * @return {Matrix} results + * @override + */ +MatrixNode.prototype.eval = function() { + // evaluate all nodes in the 2d array, and merge the results into a matrix + var nodes = this.nodes, + results = [], + mergeNeeded = false; -(function () { - /** - * Evaluate the array - * @return {Matrix} results - * @override - */ - MatrixNode.prototype.eval = function() { - // evaluate all nodes in the 2d array, and merge the results into a matrix - var nodes = this.nodes, - results = [], - mergeNeeded = false; - - for (var r = 0, rows = nodes.length; r < rows; r++) { - var nodes_r = nodes[r]; - var results_r = []; - for (var c = 0, cols = nodes_r.length; c < cols; c++) { - var results_rc = nodes_r[c].eval(); - if (results_rc instanceof Matrix || - results_rc instanceof Range || - Array.isArray(results_rc)) { - mergeNeeded = true; - } - results_r[c] = results_rc; + for (var r = 0, rows = nodes.length; r < rows; r++) { + var nodes_r = nodes[r]; + var results_r = []; + for (var c = 0, cols = nodes_r.length; c < cols; c++) { + var results_rc = nodes_r[c].eval(); + if (collection.isCollection(results_rc)) { + mergeNeeded = true; } - results[r] = results_r; + results_r[c] = results_rc; } - - if (mergeNeeded) { - results = merge(results); - } - - return new Matrix(results); - }; - - /** - * Find all nodes matching given filter - * @param {Object} filter See Node.find for a description of the filter options - * @returns {Node[]} nodes - */ - MatrixNode.prototype.find = function (filter) { - var results = []; - - // check itself - if (this.match(filter)) { - results.push(this); - } - - // search in all nodes - var nodes = this.nodes; - for (var r = 0, rows = nodes.length; r < rows; r++) { - var nodes_r = nodes[r]; - for (var c = 0, cols = nodes_r.length; c < cols; c++) { - results = results.concat(nodes_r[c].find(filter)); - } - } - - return results; - }; - - /** - * Merge nested Matrices in a two dimensional Array. - * @param {Array} array Two-dimensional array containing Matrices - * @return {Array} merged The merged array (two-dimensional) - */ - function merge (array) { - var merged = []; - var rows = array.length; - for (var r = 0; r < rows; r++) { - var array_r = array[r]; - var cols = array_r.length; - var submatrix = null; - var submatrixRows = null; - for (var c = 0; c < cols; c++) { - var entry = math.clone(array_r[c]); - var size; - if (entry instanceof Matrix) { - // get the data from the matrix - size = entry.size(); - entry = entry.valueOf(); - if (size.length == 1) { - entry = [entry]; - size = [1, size[0]]; - } - else if (size.length > 2) { - throw new Error('Cannot merge a multi dimensional matrix'); - } - } - else if (entry instanceof Range) { - // change range into an 1xn matrix - entry = [entry.valueOf()]; - size = [1, entry[0].length]; - } - else if (Array.isArray(entry)) { - // change array into a 1xn matrix - size = [1, entry.length]; - entry = [entry]; - } - else { - // change scalar into a 1x1 matrix - size = [1, 1]; - entry = [[entry]]; - } - - // check the height of this row - if (submatrix == null) { - // first entry - submatrix = entry; - submatrixRows = size[0]; - } - else if (size[0] == submatrixRows) { - // merge - for (var s = 0; s < submatrixRows; s++) { - submatrix[s] = submatrix[s].concat(entry[s]); - } - } - else { - // no good... - throw new Error('Dimension mismatch ' + - '(' + size[0] + ' != ' + submatrixRows + ')'); - } - } - - // merge the submatrix - merged = merged.concat(submatrix); - } - - return merged; + results[r] = results_r; } - /** - * Get string representation - * @return {String} str - * @override - */ - MatrixNode.prototype.toString = function() { - return util.formatArray(this.nodes); - }; -})(); \ No newline at end of file + if (mergeNeeded) { + results = merge(results); + } + + return new Matrix(results); +}; + +/** + * Find all nodes matching given filter + * @param {Object} filter See Node.find for a description of the filter options + * @returns {Node[]} nodes + */ +MatrixNode.prototype.find = function (filter) { + var results = []; + + // check itself + if (this.match(filter)) { + results.push(this); + } + + // search in all nodes + var nodes = this.nodes; + for (var r = 0, rows = nodes.length; r < rows; r++) { + var nodes_r = nodes[r]; + for (var c = 0, cols = nodes_r.length; c < cols; c++) { + results = results.concat(nodes_r[c].find(filter)); + } + } + + return results; +}; + +/** + * Merge nested Matrices in a two dimensional Array. + * @param {Array} array Two-dimensional array containing Matrices + * @return {Array} merged The merged array (two-dimensional) + */ +function merge (array) { + var merged = []; + var rows = array.length; + for (var r = 0; r < rows; r++) { + var array_r = array[r]; + var cols = array_r.length; + var submatrix = null; + var submatrixRows = null; + for (var c = 0; c < cols; c++) { + var entry = object.clone(array_r[c]); + var size; + if (entry instanceof Matrix) { + // get the data from the matrix + size = entry.size(); + entry = entry.valueOf(); + if (size.length == 1) { + entry = [entry]; + size = [1, size[0]]; + } + else if (size.length > 2) { + throw new Error('Cannot merge a multi dimensional matrix'); + } + } + else if (entry instanceof Range) { + // change range into an 1xn matrix + entry = [entry.valueOf()]; + size = [1, entry[0].length]; + } + else if (Array.isArray(entry)) { + // change array into a 1xn matrix + size = [1, entry.length]; + entry = [entry]; + } + else { + // change scalar into a 1x1 matrix + size = [1, 1]; + entry = [[entry]]; + } + + // check the height of this row + if (submatrix == null) { + // first entry + submatrix = entry; + submatrixRows = size[0]; + } + else if (size[0] == submatrixRows) { + // merge + for (var s = 0; s < submatrixRows; s++) { + submatrix[s] = submatrix[s].concat(entry[s]); + } + } + else { + // no good... + throw new Error('Dimension mismatch ' + + '(' + size[0] + ' != ' + submatrixRows + ')'); + } + } + + // merge the submatrix + merged = merged.concat(submatrix); + } + + return merged; +} + +/** + * Get string representation + * @return {String} str + * @override + */ +MatrixNode.prototype.toString = function() { + return string.format(this.nodes); +}; + +module.exports = MatrixNode; diff --git a/src/expr/node/Node.js b/src/expr/node/Node.js index 2d081739e..12182c083 100644 --- a/src/expr/node/Node.js +++ b/src/expr/node/Node.js @@ -3,8 +3,6 @@ */ function Node() {} -math.expr.node.Node = Node; - /** * Evaluate the node * @return {*} result @@ -69,3 +67,5 @@ Node.prototype.match = function (filter) { Node.prototype.toString = function() { return ''; }; + +module.exports = Node; diff --git a/src/expr/node/OperatorNode.js b/src/expr/node/OperatorNode.js index 01f1c2751..6b851056d 100644 --- a/src/expr/node/OperatorNode.js +++ b/src/expr/node/OperatorNode.js @@ -1,3 +1,5 @@ +var Node = require('./Node.js'); + /** * @constructor OperatorNode * An operator with two arguments, like 2+3 @@ -13,8 +15,6 @@ function OperatorNode (name, fn, params) { OperatorNode.prototype = new Node(); -math.expr.node.OperatorNode = OperatorNode; - /** * Evaluate the parameters * @return {*} result @@ -56,14 +56,16 @@ OperatorNode.prototype.find = function (filter) { OperatorNode.prototype.toString = function() { var params = this.params; - // special case: unary minus - if (this.fn === math.unary) { - return '-' + params[0].toString(); - } - switch (params.length) { - case 1: // for example '5!' - return params[0].toString() + this.name; + case 1: + if (this.name == '-') { + // special case: unary minus + return '-' + params[0].toString(); + } + else { + // for example '5!' + return params[0].toString() + this.name; + } case 2: // for example '2+3' var lhs = params[0].toString(); @@ -80,3 +82,5 @@ OperatorNode.prototype.toString = function() { return this.name + '(' + this.params.join(', ') + ')'; } }; + +module.exports = OperatorNode; diff --git a/src/expr/node/ParamsNode.js b/src/expr/node/ParamsNode.js index 2c5e9075b..7d97ae11b 100644 --- a/src/expr/node/ParamsNode.js +++ b/src/expr/node/ParamsNode.js @@ -1,3 +1,7 @@ +var math = require('../../math.js'), + Node = require('./Node.js'), + SymbolNode = require('./SymbolNode.js').SymbolNode; + /** * @constructor ParamsNode * invoke a list with parameters on the results of a node @@ -15,7 +19,7 @@ function ParamsNode (object, params, paramScopes) { this.hasContextParams = false; if (params) { var filter = { - type: math.type.SymbolNode, + type: SymbolNode, properties: { name: 'end' } @@ -32,8 +36,6 @@ function ParamsNode (object, params, paramScopes) { ParamsNode.prototype = new Node(); -math.expr.node.ParamsNode = ParamsNode; - /** * Evaluate the parameters * @return {*} result @@ -130,3 +132,5 @@ ParamsNode.prototype.toString = function() { } return str; }; + +module.exports = ParamsNode; diff --git a/src/expr/node/SymbolNode.js b/src/expr/node/SymbolNode.js index dfd7680b0..ed1dfeaa8 100644 --- a/src/expr/node/SymbolNode.js +++ b/src/expr/node/SymbolNode.js @@ -1,8 +1,10 @@ +var Node = require('./Node.js'); + /** * @constructor SymbolNode * A symbol node can hold and resolve a symbol * @param {String} name - * @param {math.expr.Scope} scope + * @param {Scope} scope * @extends {Node} */ function SymbolNode(name, scope) { @@ -12,8 +14,6 @@ function SymbolNode(name, scope) { SymbolNode.prototype = new Node(); -math.expr.node.SymbolNode = SymbolNode; - /** * Evaluate the symbol. Throws an error when the symbol is undefined. * @return {*} result @@ -38,3 +38,5 @@ SymbolNode.prototype.eval = function() { SymbolNode.prototype.toString = function() { return this.name; }; + +module.exports = SymbolNode; diff --git a/src/expr/node/UpdateNode.js b/src/expr/node/UpdateNode.js index 52733fc9d..b33d596f6 100644 --- a/src/expr/node/UpdateNode.js +++ b/src/expr/node/UpdateNode.js @@ -1,3 +1,7 @@ +var math = require('../../math.js'), + Node = require('./Node.js'), + SymbolNode = require('./SymbolNode.js').SymbolNode; + /** * @constructor UpdateNode * Update a symbol value, like a(2,3) = 4.5 @@ -7,7 +11,7 @@ * @param {Scope[]} paramScopes A scope for every parameter, where the * index variable 'end' can be defined. * @param {Node} expr The expression defining the symbol - * @param {math.expr.Scope} scope Scope to store the result + * @param {Scope} scope Scope to store the result */ function UpdateNode(name, params, paramScopes, expr, scope) { this.name = name; @@ -19,7 +23,7 @@ function UpdateNode(name, params, paramScopes, expr, scope) { // check whether any of the params expressions uses the context symbol 'end' this.hasContextParams = false; var filter = { - type: math.type.SymbolNode, + type: SymbolNode, properties: { name: 'end' } @@ -34,8 +38,6 @@ function UpdateNode(name, params, paramScopes, expr, scope) { UpdateNode.prototype = new Node(); -math.expr.node.UpdateNode = UpdateNode; - /** * Evaluate the assignment * @return {*} result @@ -46,7 +48,6 @@ UpdateNode.prototype.eval = function() { } var result; - var params = this.params; // test if definition is currently undefined var prevResult = this.scope.get(this.name); @@ -139,3 +140,5 @@ UpdateNode.prototype.toString = function() { return str; }; + +module.exports = UpdateNode; diff --git a/src/expr/node/handlers.js b/src/expr/node/handlers.js new file mode 100644 index 000000000..d28776282 --- /dev/null +++ b/src/expr/node/handlers.js @@ -0,0 +1,4 @@ +/** + * Custom node handlers, + * (can be added to the exports object) + */ diff --git a/src/expr/node/index.js b/src/expr/node/index.js new file mode 100644 index 000000000..68ffd9bd5 --- /dev/null +++ b/src/expr/node/index.js @@ -0,0 +1,12 @@ +exports.AssignmentNode = require('./AssignmentNode.js'); +exports.BlockNode = require('./BlockNode.js'); +exports.ConstantNode = require('./ConstantNode.js'); +exports.FunctionNode = require('./FunctionNode.js'); +exports.MatrixNode = require('./MatrixNode.js'); +exports.Node = require('./Node.js'); +exports.OperatorNode = require('./OperatorNode.js'); +exports.ParamsNode = require('./ParamsNode.js'); +exports.SymbolNode = require('./SymbolNode.js'); +exports.UpdateNode = require('./UpdateNode.js'); + +exports.handlers = require('./handlers.js'); diff --git a/src/function/arithmetic/abs.js b/src/function/arithmetic/abs.js index 5031d7062..a83587f0e 100644 --- a/src/function/arithmetic/abs.js +++ b/src/function/arithmetic/abs.js @@ -1,34 +1,46 @@ -/** - * Calculate the absolute value of a value. - * - * abs(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ -math.abs = function abs(x) { - if (arguments.length != 1) { - throw newArgumentsError('abs', arguments.length, 1); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (isNumber(x)) { - return Math.abs(x); - } + Complex = require('../../type/Complex.js'), + Matrix = require('../../type/Matrix.js'), + collection = require('../../type/collection.js'), - if (x instanceof Complex) { - return Math.sqrt(x.re * x.re + x.im * x.im); - } + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isCollection = collection.isCollection; - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.abs); - } + /** + * Calculate the absolute value of a value. + * + * abs(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + */ + math.abs = function abs(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('abs', arguments.length, 1); + } - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.abs(x.valueOf()); - } + if (isNumber(x)) { + return Math.abs(x); + } - throw newUnsupportedTypeError('abs', x); + if (isComplex(x)) { + return Math.sqrt(x.re * x.re + x.im * x.im); + } + + if (isCollection(x)) { + return collection.map(x, abs); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return abs(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('abs', x); + }; }; diff --git a/src/function/arithmetic/add.js b/src/function/arithmetic/add.js index 2e560ea79..ab28653bf 100644 --- a/src/function/arithmetic/add.js +++ b/src/function/arithmetic/add.js @@ -1,83 +1,97 @@ -/** - * Add two values - * - * x + y - * add(x, y) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Unit | String | Array | Matrix} x - * @param {Number | Complex | Unit | String | Array | Matrix} y - * @return {Number | Complex | Unit | String | Array | Matrix} res - */ -math.add = function add(x, y) { - if (arguments.length != 2) { - throw newArgumentsError('add', arguments.length, 2); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (isNumber(x)) { - if (isNumber(y)) { - // number + number + Complex = require('../../type/Complex.js'), + Matrix = require('../../type/Matrix.js'), + Unit = require('../../type/Unit.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isString = util.string.isString, + isComplex = Complex.isComplex, + isUnit = Unit.isUnit, + isCollection = collection.isCollection; + + /** + * Add two values + * + * x + y + * add(x, y) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Unit | String | Array | Matrix} x + * @param {Number | Complex | Unit | String | Array | Matrix} y + * @return {Number | Complex | Unit | String | Array | Matrix} res + */ + math.add = function add(x, y) { + if (arguments.length != 2) { + throw new util.error.ArgumentsError('add', arguments.length, 2); + } + + if (isNumber(x)) { + if (isNumber(y)) { + // number + number + return x + y; + } + else if (isComplex(y)) { + // number + complex + return Complex.create( + x + y.re, + y.im + ) + } + } + else if (isComplex(x)) { + if (isNumber(y)) { + // complex + number + return Complex.create( + x.re + y, + x.im + ) + } + else if (isComplex(y)) { + // complex + complex + return Complex.create( + x.re + y.re, + x.im + y.im + ); + } + } + else if (isUnit(x)) { + if (isUnit(y)) { + if (!x.equalBase(y)) { + throw new Error('Units do not match'); + } + + if (x.value == null) { + throw new Error('Unit on left hand side of operator + has an undefined value'); + } + + if (y.value == null) { + throw new Error('Unit on right hand side of operator + has an undefined value'); + } + + var res = x.clone(); + res.value += y.value; + res.fixPrefix = false; + return res; + } + } + + if (isString(x) || isString(y)) { return x + y; } - else if (y instanceof Complex) { - // number + complex - return Complex.create( - x + y.re, - y.im - ) + + if (isCollection(x) || isCollection(y)) { + return collection.map2(x, y, add); } - } - else if (x instanceof Complex) { - if (isNumber(y)) { - // complex + number - return Complex.create( - x.re + y, - x.im - ) + + if (x.valueOf() !== x || y.valueOf() !== y) { + // fallback on the objects primitive value + return add(x.valueOf(), y.valueOf()); } - else if (y instanceof Complex) { - // complex + complex - return Complex.create( - x.re + y.re, - x.im + y.im - ); - } - } - else if (x instanceof Unit) { - if (y instanceof Unit) { - if (!x.equalBase(y)) { - throw new Error('Units do not match'); - } - if (x.value == null) { - throw new Error('Unit on left hand side of operator + has an undefined value'); - } - - if (y.value == null) { - throw new Error('Unit on right hand side of operator + has an undefined value'); - } - - var res = x.clone(); - res.value += y.value; - res.fixPrefix = false; - return res; - } - } - - if (isString(x) || isString(y)) { - return x + y; - } - - if (Array.isArray(x) || x instanceof Matrix || - Array.isArray(y) || y instanceof Matrix) { - return util.map2(x, y, math.add); - } - - if (x.valueOf() !== x || y.valueOf() !== y) { - // fallback on the objects primitive value - return math.add(x.valueOf(), y.valueOf()); - } - - throw newUnsupportedTypeError('add', x, y); + throw new util.error.UnsupportedTypeError('add', x, y); + }; }; diff --git a/src/function/arithmetic/ceil.js b/src/function/arithmetic/ceil.js index 7b6b55618..469335a24 100644 --- a/src/function/arithmetic/ceil.js +++ b/src/function/arithmetic/ceil.js @@ -1,37 +1,48 @@ -/** - * Round a value towards plus infinity - * - * ceil(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ -math.ceil = function ceil(x) { - if (arguments.length != 1) { - throw newArgumentsError('ceil', arguments.length, 1); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (isNumber(x)) { - return Math.ceil(x); - } + Complex = require('../../type/Complex.js'), + collection = require('../../type/collection.js'), - if (x instanceof Complex) { - return Complex.create ( - Math.ceil(x.re), - Math.ceil(x.im) - ); - } + isNumber = util.number.isNumber, + isCollection =collection.isCollection, + isComplex = Complex.isComplex; - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.ceil); - } + /** + * Round a value towards plus infinity + * + * ceil(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + */ + math.ceil = function ceil(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('ceil', arguments.length, 1); + } - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.ceil(x.valueOf()); - } + if (isNumber(x)) { + return Math.ceil(x); + } - throw newUnsupportedTypeError('ceil', x); + if (isComplex(x)) { + return Complex.create ( + Math.ceil(x.re), + Math.ceil(x.im) + ); + } + + if (isCollection(x)) { + return collection.map(x, ceil); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return ceil(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('ceil', x); + }; }; diff --git a/src/function/arithmetic/cube.js b/src/function/arithmetic/cube.js index 1d7540ca3..8bccce8f7 100644 --- a/src/function/arithmetic/cube.js +++ b/src/function/arithmetic/cube.js @@ -1,35 +1,46 @@ -/** - * Compute the cube of a value - * - * x .* x .* x - * cube(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ -math.cube = function cube(x) { - if (arguments.length != 1) { - throw newArgumentsError('cube', arguments.length, 1); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (isNumber(x)) { - return x * x * x; - } + Complex = require('../../type/Complex.js'), + collection = require('../../type/collection.js'), - if (x instanceof Complex) { - return math.multiply(math.multiply(x, x), x); - } + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isCollection = collection.isCollection; - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.cube); - } + /** + * Compute the cube of a value + * + * x .* x .* x + * cube(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + */ + math.cube = function cube(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('cube', arguments.length, 1); + } - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.cube(x.valueOf()); - } + if (isNumber(x)) { + return x * x * x; + } - throw newUnsupportedTypeError('cube', x); + if (isComplex(x)) { + return math.multiply(math.multiply(x, x), x); + } + + if (isCollection(x)) { + return collection.map(x, cube); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return cube(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('cube', x); + }; }; diff --git a/src/function/arithmetic/divide.js b/src/function/arithmetic/divide.js index bfcf56fde..66b5ef11f 100644 --- a/src/function/arithmetic/divide.js +++ b/src/function/arithmetic/divide.js @@ -1,95 +1,109 @@ -/** - * Divide two values. - * - * x / y - * divide(x, y) - * - * @param {Number | Complex | Unit | Array | Matrix} x - * @param {Number | Complex} y - * @return {Number | Complex | Unit | Array | Matrix} res - */ -math.divide = function divide(x, y) { - if (arguments.length != 2) { - throw newArgumentsError('divide', arguments.length, 2); - } +module.exports = function(math) { + var util = require('../../util/index.js'), - if (isNumber(x)) { - if (isNumber(y)) { - // number / number - return x / y; - } - else if (y instanceof Complex) { - // number / complex - return _divideComplex(new Complex(x, 0), y); - } - } + Complex = require('../../type/Complex.js'), + Matrix = require('../../type/Matrix.js'), + Unit = require('../../type/Unit.js'), + collection = require('../../type/collection.js'), - if (x instanceof Complex) { - if (isNumber(y)) { - // complex / number - return _divideComplex(x, new Complex(y, 0)); - } - else if (y instanceof Complex) { - // complex / complex - return _divideComplex(x, y); - } - } + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isUnit = Unit.isUnit, + isCollection = collection.isCollection; - if (x instanceof Unit) { - if (isNumber(y)) { - var res = x.clone(); - res.value /= y; - return res; + /** + * Divide two values. + * + * x / y + * divide(x, y) + * + * @param {Number | Complex | Unit | Array | Matrix} x + * @param {Number | Complex} y + * @return {Number | Complex | Unit | Array | Matrix} res + */ + math.divide = function divide(x, y) { + if (arguments.length != 2) { + throw new util.error.ArgumentsError('divide', arguments.length, 2); } - } - if (Array.isArray(x) || x instanceof Matrix) { - if (Array.isArray(y) || y instanceof Matrix) { + if (isNumber(x)) { + if (isNumber(y)) { + // number / number + return x / y; + } + else if (isComplex(y)) { + // number / complex + return _divideComplex(new Complex(x, 0), y); + } + } + + if (isComplex(x)) { + if (isNumber(y)) { + // complex / number + return _divideComplex(x, new Complex(y, 0)); + } + else if (isComplex(y)) { + // complex / complex + return _divideComplex(x, y); + } + } + + if (isUnit(x)) { + if (isNumber(y)) { + var res = x.clone(); + res.value /= y; + return res; + } + } + + if (isCollection(x)) { + if (isCollection(y)) { + // TODO: implement matrix right division using pseudo inverse + // http://www.mathworks.nl/help/matlab/ref/mrdivide.html + // http://www.gnu.org/software/octave/doc/interpreter/Arithmetic-Ops.html + // http://stackoverflow.com/questions/12263932/how-does-gnu-octave-matrix-division-work-getting-unexpected-behaviour + return math.multiply(x, math.inv(y)); + } + else { + // matrix / scalar + return collection.map2(x, y, divide); + } + } + + if (isCollection(y)) { // TODO: implement matrix right division using pseudo inverse - // http://www.mathworks.nl/help/matlab/ref/mrdivide.html - // http://www.gnu.org/software/octave/doc/interpreter/Arithmetic-Ops.html - // http://stackoverflow.com/questions/12263932/how-does-gnu-octave-matrix-division-work-getting-unexpected-behaviour return math.multiply(x, math.inv(y)); } + + if (x.valueOf() !== x || y.valueOf() !== y) { + // fallback on the objects primitive value + return divide(x.valueOf(), y.valueOf()); + } + + throw new util.error.UnsupportedTypeError('divide', x, y); + }; + + /** + * Divide two complex numbers. x / y or divide(x, y) + * @param {Complex} x + * @param {Complex} y + * @return {Complex} res + * @private + */ + function _divideComplex (x, y) { + var den = y.re * y.re + y.im * y.im; + if (den != 0) { + return Complex.create( + (x.re * y.re + x.im * y.im) / den, + (x.im * y.re - x.re * y.im) / den + ); + } else { - // matrix / scalar - return util.map2(x, y, math.divide); + // both y.re and y.im are zero + return Complex.create( + (x.re != 0) ? (x.re / 0) : 0, + (x.im != 0) ? (x.im / 0) : 0 + ); } } - - if (Array.isArray(y) || y instanceof Matrix) { - // TODO: implement matrix right division using pseudo inverse - return math.multiply(x, math.inv(y)); - } - - if (x.valueOf() !== x || y.valueOf() !== y) { - // fallback on the objects primitive value - return math.divide(x.valueOf(), y.valueOf()); - } - - throw newUnsupportedTypeError('divide', x, y); }; - -/** - * Divide two complex numbers. x / y or divide(x, y) - * @param {Complex} x - * @param {Complex} y - * @return {Complex} res - * @private - */ -function _divideComplex (x, y) { - var den = y.re * y.re + y.im * y.im; - if (den != 0) { - return Complex.create( - (x.re * y.re + x.im * y.im) / den, - (x.im * y.re - x.re * y.im) / den - ); - } - else { - // both y.re and y.im are zero - return Complex.create( - (x.re != 0) ? (x.re / 0) : 0, - (x.im != 0) ? (x.im / 0) : 0 - ); - } -} diff --git a/src/function/arithmetic/edivide.js b/src/function/arithmetic/edivide.js index 89670d8ce..dcd763b62 100644 --- a/src/function/arithmetic/edivide.js +++ b/src/function/arithmetic/edivide.js @@ -1,17 +1,22 @@ -/** - * Divide two values element wise. - * - * x ./ y - * edivide(x, y) - * - * @param {Number | Complex | Unit | Array | Matrix} x - * @param {Number | Complex | Unit | Array | Matrix} y - * @return {Number | Complex | Unit | Array | Matrix} res - */ -math.edivide = function edivide(x, y) { - if (arguments.length != 2) { - throw newArgumentsError('edivide', arguments.length, 2); - } +module.exports = function (math) { + var util = require('../../util/index.js'), + collection = require('../../type/collection.js'); - return util.deepMap2(x, y, math.divide); + /** + * Divide two values element wise. + * + * x ./ y + * edivide(x, y) + * + * @param {Number | Complex | Unit | Array | Matrix} x + * @param {Number | Complex | Unit | Array | Matrix} y + * @return {Number | Complex | Unit | Array | Matrix} res + */ + math.edivide = function edivide(x, y) { + if (arguments.length != 2) { + throw new util.error.ArgumentsError('edivide', arguments.length, 2); + } + + return collection.deepMap2(x, y, math.divide); + }; }; diff --git a/src/function/arithmetic/emultiply.js b/src/function/arithmetic/emultiply.js index 76e6fca50..559fa65e9 100644 --- a/src/function/arithmetic/emultiply.js +++ b/src/function/arithmetic/emultiply.js @@ -1,17 +1,22 @@ -/** - * Multiply two values element wise. - * - * x .* y - * emultiply(x, y) - * - * @param {Number | Complex | Unit | Array | Matrix} x - * @param {Number | Complex | Unit | Array | Matrix} y - * @return {Number | Complex | Unit | Array | Matrix} res - */ -math.emultiply = function emultiply(x, y) { - if (arguments.length != 2) { - throw newArgumentsError('emultiply', arguments.length, 2); - } +module.exports = function (math) { + var util = require('../../util/index.js'), + collection = require('../../type/collection.js'); - return util.deepMap2(x, y, math.multiply); + /** + * Multiply two values element wise. + * + * x .* y + * emultiply(x, y) + * + * @param {Number | Complex | Unit | Array | Matrix} x + * @param {Number | Complex | Unit | Array | Matrix} y + * @return {Number | Complex | Unit | Array | Matrix} res + */ + math.emultiply = function emultiply(x, y) { + if (arguments.length != 2) { + throw new util.error.ArgumentsError('emultiply', arguments.length, 2); + } + + return collection.deepMap2(x, y, math.multiply); + }; }; diff --git a/src/function/arithmetic/epow.js b/src/function/arithmetic/epow.js index baf87f767..59990bfc3 100644 --- a/src/function/arithmetic/epow.js +++ b/src/function/arithmetic/epow.js @@ -1,17 +1,22 @@ -/** - * Calculates the power of x to y element wise - * - * x .^ y - * epow(x, y) - * - * @param {Number | Complex | Unit | Array | Matrix} x - * @param {Number | Complex | Unit | Array | Matrix} y - * @return {Number | Complex | Unit | Array | Matrix} res - */ -math.epow = function epow(x, y) { - if (arguments.length != 2) { - throw newArgumentsError('epow', arguments.length, 2); - } +module.exports = function (math) { + var util = require('../../util/index.js'), + collection = require('../../type/collection.js'); - return util.deepMap2(x, y, math.pow); + /** + * Calculates the power of x to y element wise + * + * x .^ y + * epow(x, y) + * + * @param {Number | Complex | Unit | Array | Matrix} x + * @param {Number | Complex | Unit | Array | Matrix} y + * @return {Number | Complex | Unit | Array | Matrix} res + */ + math.epow = function epow(x, y) { + if (arguments.length != 2) { + throw new util.error.ArgumentsError('epow', arguments.length, 2); + } + + return collection.deepMap2(x, y, math.pow); + }; }; diff --git a/src/function/arithmetic/equal.js b/src/function/arithmetic/equal.js index 64d98b8fc..a6c152d35 100644 --- a/src/function/arithmetic/equal.js +++ b/src/function/arithmetic/equal.js @@ -1,58 +1,71 @@ -/** - * Check if value x equals y, - * - * x == y - * equal(x, y) - * - * For matrices, the function is evaluated element wise. - * In case of complex numbers, x.re must equal y.re, and x.im must equal y.im. - * - * @param {Number | Complex | Unit | String | Array | Matrix} x - * @param {Number | Complex | Unit | String | Array | Matrix} y - * @return {Boolean | Array | Matrix} res - */ -math.equal = function equal(x, y) { - if (arguments.length != 2) { - throw newArgumentsError('equal', arguments.length, 2); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (isNumber(x)) { - if (isNumber(y)) { + Complex = require('../../type/Complex.js'), + Unit = require('../../type/Unit.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isString = util.string.isString, + isComplex = Complex.isComplex, + isUnit = Unit.isUnit, + isCollection = collection.isCollection; + + /** + * Check if value x equals y, + * + * x == y + * equal(x, y) + * + * For matrices, the function is evaluated element wise. + * In case of complex numbers, x.re must equal y.re, and x.im must equal y.im. + * + * @param {Number | Complex | Unit | String | Array | Matrix} x + * @param {Number | Complex | Unit | String | Array | Matrix} y + * @return {Boolean | Array | Matrix} res + */ + math.equal = function equal(x, y) { + if (arguments.length != 2) { + throw new util.error.ArgumentsError('equal', arguments.length, 2); + } + + if (isNumber(x)) { + if (isNumber(y)) { + return x == y; + } + else if (isComplex(y)) { + return (x == y.re) && (y.im == 0); + } + } + if (isComplex(x)) { + if (isNumber(y)) { + return (x.re == y) && (x.im == 0); + } + else if (isComplex(y)) { + return (x.re == y.re) && (x.im == y.im); + } + } + + if ((isUnit(x)) && (isUnit(y))) { + if (!x.equalBase(y)) { + throw new Error('Cannot compare units with different base'); + } + return x.value == y.value; + } + + if (isString(x) || isString(y)) { return x == y; } - else if (y instanceof Complex) { - return (x == y.re) && (y.im == 0); + + if (isCollection(x) || isCollection(y)) { + return collection.map2(x, y, equal); } - } - if (x instanceof Complex) { - if (isNumber(y)) { - return (x.re == y) && (x.im == 0); + + if (x.valueOf() !== x || y.valueOf() !== y) { + // fallback on the objects primitive values + return equal(x.valueOf(), y.valueOf()); } - else if (y instanceof Complex) { - return (x.re == y.re) && (x.im == y.im); - } - } - if ((x instanceof Unit) && (y instanceof Unit)) { - if (!x.equalBase(y)) { - throw new Error('Cannot compare units with different base'); - } - return x.value == y.value; - } - - if (isString(x) || isString(y)) { - return x == y; - } - - if (Array.isArray(x) || x instanceof Matrix || - Array.isArray(y) || y instanceof Matrix) { - return util.map2(x, y, math.equal); - } - - if (x.valueOf() !== x || y.valueOf() !== y) { - // fallback on the objects primitive values - return equal(x.valueOf(), y.valueOf()); - } - - throw newUnsupportedTypeError('equal', x, y); + throw new util.error.UnsupportedTypeError('equal', x, y); + }; }; diff --git a/src/function/arithmetic/exp.js b/src/function/arithmetic/exp.js index cee9d133c..9bf1a6a69 100644 --- a/src/function/arithmetic/exp.js +++ b/src/function/arithmetic/exp.js @@ -1,37 +1,49 @@ -/** - * Calculate the exponent of a value - * - * exp(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ -math.exp = function exp (x) { - if (arguments.length != 1) { - throw newArgumentsError('exp', arguments.length, 1); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (isNumber(x)) { - return Math.exp(x); - } - if (x instanceof Complex) { - var r = Math.exp(x.re); - return Complex.create( - r * Math.cos(x.im), - r * Math.sin(x.im) - ); - } + Complex = require('../../type/Complex.js'), + Matrix = require('../../type/Matrix.js'), + collection = require('../../type/collection.js'), - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.exp); - } + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isCollection = collection.isCollection; - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.exp(x.valueOf()); - } + /** + * Calculate the exponent of a value + * + * exp(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + */ + math.exp = function exp (x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('exp', arguments.length, 1); + } - throw newUnsupportedTypeError('exp', x); + if (isNumber(x)) { + return Math.exp(x); + } + if (isComplex(x)) { + var r = Math.exp(x.re); + return Complex.create( + r * Math.cos(x.im), + r * Math.sin(x.im) + ); + } + + if (isCollection(x)) { + return collection.map(x, exp); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return exp(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('exp', x); + }; }; diff --git a/src/function/arithmetic/fix.js b/src/function/arithmetic/fix.js index 9918a2f8b..c586aeaa5 100644 --- a/src/function/arithmetic/fix.js +++ b/src/function/arithmetic/fix.js @@ -1,37 +1,48 @@ -/** - * Round a value towards zero - * - * fix(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ -math.fix = function fix(x) { - if (arguments.length != 1) { - throw newArgumentsError('fix', arguments.length, 1); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (isNumber(x)) { - return (x > 0) ? Math.floor(x) : Math.ceil(x); - } + Complex = require('../../type/Complex.js'), + collection = require('../../type/collection.js'), - if (x instanceof Complex) { - return Complex.create( - (x.re > 0) ? Math.floor(x.re) : Math.ceil(x.re), - (x.im > 0) ? Math.floor(x.im) : Math.ceil(x.im) - ); - } + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isCollection = collection.isCollection; - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.fix); - } + /** + * Round a value towards zero + * + * fix(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + */ + math.fix = function fix(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('fix', arguments.length, 1); + } - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.fix(x.valueOf()); - } + if (isNumber(x)) { + return (x > 0) ? Math.floor(x) : Math.ceil(x); + } - throw newUnsupportedTypeError('fix', x); + if (isComplex(x)) { + return Complex.create( + (x.re > 0) ? Math.floor(x.re) : Math.ceil(x.re), + (x.im > 0) ? Math.floor(x.im) : Math.ceil(x.im) + ); + } + + if (isCollection(x)) { + return collection.map(x, fix); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return fix(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('fix', x); + }; }; diff --git a/src/function/arithmetic/floor.js b/src/function/arithmetic/floor.js index de274be26..92281c133 100644 --- a/src/function/arithmetic/floor.js +++ b/src/function/arithmetic/floor.js @@ -1,37 +1,48 @@ -/** - * Round a value towards minus infinity - * - * floor(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ -math.floor = function floor(x) { - if (arguments.length != 1) { - throw newArgumentsError('floor', arguments.length, 1); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (isNumber(x)) { - return Math.floor(x); - } + Complex = require('../../type/Complex.js'), + collection = require('../../type/collection.js'), - if (x instanceof Complex) { - return Complex.create ( - Math.floor(x.re), - Math.floor(x.im) - ); - } + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isCollection = collection.isCollection; - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.floor); - } + /** + * Round a value towards minus infinity + * + * floor(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + */ + math.floor = function floor(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('floor', arguments.length, 1); + } - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.floor(x.valueOf()); - } + if (isNumber(x)) { + return Math.floor(x); + } - throw newUnsupportedTypeError('floor', x); + if (isComplex(x)) { + return Complex.create ( + Math.floor(x.re), + Math.floor(x.im) + ); + } + + if (isCollection(x)) { + return collection.map(x, floor); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return floor(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('floor', x); + }; }; diff --git a/src/function/arithmetic/gcd.js b/src/function/arithmetic/gcd.js index 0f02d5194..90093cb85 100644 --- a/src/function/arithmetic/gcd.js +++ b/src/function/arithmetic/gcd.js @@ -1,57 +1,66 @@ -/** - * Calculate the greatest common divisor for two or more values or arrays. - * - * gcd(a, b) - * gcd(a, b, c, ...) - * - * For matrices, the function is evaluated element wise. - * - * @param {... Number | Array | Matrix} args two or more integer numbers - * @return {Number | Array | Matrix} greatest common divisor - */ -math.gcd = function gcd(args) { - var a = arguments[0], - b = arguments[1], - t; +module.exports = function (math) { + var util = require('../../util/index.js'), - if (arguments.length == 2) { - // two arguments - if (isNumber(a) && isNumber(b)) { - if (!isInteger(a) || !isInteger(b)) { - throw new Error('Parameters in function gcd must be integer numbers'); + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isInteger = util.number.isInteger, + isCollection = collection.isCollection; + + /** + * Calculate the greatest common divisor for two or more values or arrays. + * + * gcd(a, b) + * gcd(a, b, c, ...) + * + * For matrices, the function is evaluated element wise. + * + * @param {... Number | Array | Matrix} args two or more integer numbers + * @return {Number | Array | Matrix} greatest common divisor + */ + math.gcd = function gcd(args) { + var a = arguments[0], + b = arguments[1], + t; + + if (arguments.length == 2) { + // two arguments + if (isNumber(a) && isNumber(b)) { + if (!isInteger(a) || !isInteger(b)) { + throw new Error('Parameters in function gcd must be integer numbers'); + } + + // http://en.wikipedia.org/wiki/Euclidean_algorithm + while (b != 0) { + t = b; + b = a % t; + a = t; + } + return Math.abs(a); } - // http://en.wikipedia.org/wiki/Euclidean_algorithm - while (b != 0) { - t = b; - b = a % t; - a = t; + // evaluate gcd element wise + if (isCollection(a) || isCollection(b)) { + return collection.map2(a, b, gcd); } - return Math.abs(a); + + if (a.valueOf() !== a || b.valueOf() !== b) { + // fallback on the objects primitive value + return gcd(a.valueOf(), b.valueOf()); + } + + throw new util.error.UnsupportedTypeError('gcd', a, b); } - // evaluate gcd element wise - if (Array.isArray(a) || a instanceof Matrix || - Array.isArray(b) || b instanceof Matrix) { - return util.map2(a, b, math.gcd); + if (arguments.length > 2) { + // multiple arguments. Evaluate them iteratively + for (var i = 1; i < arguments.length; i++) { + a = gcd(a, arguments[i]); + } + return a; } - if (a.valueOf() !== a || b.valueOf() !== b) { - // fallback on the objects primitive value - return math.gcd(a.valueOf(), b.valueOf()); - } - - throw newUnsupportedTypeError('gcd', a, b); - } - - if (arguments.length > 2) { - // multiple arguments. Evaluate them iteratively - for (var i = 1; i < arguments.length; i++) { - a = math.gcd(a, arguments[i]); - } - return a; - } - - // zero or one argument - throw new SyntaxError('Function gcd expects two or more arguments'); + // zero or one argument + throw new SyntaxError('Function gcd expects two or more arguments'); + }; }; diff --git a/src/function/arithmetic/larger.js b/src/function/arithmetic/larger.js index 5f2912615..6c478059d 100644 --- a/src/function/arithmetic/larger.js +++ b/src/function/arithmetic/larger.js @@ -1,58 +1,71 @@ -/** - * Check if value x is larger y - * - * x > y - * larger(x, y) - * - * For matrices, the function is evaluated element wise. - * In case of complex numbers, the absolute values of a and b are compared. - * - * @param {Number | Complex | Unit | String | Array | Matrix} x - * @param {Number | Complex | Unit | String | Array | Matrix} y - * @return {Boolean | Array | Matrix} res - */ -math.larger = function larger(x, y) { - if (arguments.length != 2) { - throw newArgumentsError('larger', arguments.length, 2); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (isNumber(x)) { - if (isNumber(y)) { + Complex = require('../../type/Complex.js'), + Unit = require('../../type/Unit.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isString = util.string.isString, + isComplex = Complex.isComplex, + isUnit = Unit.isUnit, + isCollection = collection.isCollection; + + /** + * Check if value x is larger y + * + * x > y + * larger(x, y) + * + * For matrices, the function is evaluated element wise. + * In case of complex numbers, the absolute values of a and b are compared. + * + * @param {Number | Complex | Unit | String | Array | Matrix} x + * @param {Number | Complex | Unit | String | Array | Matrix} y + * @return {Boolean | Array | Matrix} res + */ + math.larger = function larger(x, y) { + if (arguments.length != 2) { + throw new util.error.ArgumentsError('larger', arguments.length, 2); + } + + if (isNumber(x)) { + if (isNumber(y)) { + return x > y; + } + else if (isComplex(y)) { + return x > math.abs(y); + } + } + if (isComplex(x)) { + if (isNumber(y)) { + return math.abs(x) > y; + } + else if (isComplex(y)) { + return math.abs(x) > math.abs(y); + } + } + + if ((isUnit(x)) && (isUnit(y))) { + if (!x.equalBase(y)) { + throw new Error('Cannot compare units with different base'); + } + return x.value > y.value; + } + + if (isString(x) || isString(y)) { return x > y; } - else if (y instanceof Complex) { - return x > math.abs(y); + + if (isCollection(x) || isCollection(y)) { + return collection.map2(x, y, larger); } - } - if (x instanceof Complex) { - if (isNumber(y)) { - return math.abs(x) > y; + + if (x.valueOf() !== x || y.valueOf() !== y) { + // fallback on the objects primitive values + return larger(x.valueOf(), y.valueOf()); } - else if (y instanceof Complex) { - return math.abs(x) > math.abs(y); - } - } - if ((x instanceof Unit) && (y instanceof Unit)) { - if (!x.equalBase(y)) { - throw new Error('Cannot compare units with different base'); - } - return x.value > y.value; - } - - if (isString(x) || isString(y)) { - return x > y; - } - - if (Array.isArray(x) || x instanceof Matrix || - Array.isArray(y) || y instanceof Matrix) { - return util.map2(x, y, math.larger); - } - - if (x.valueOf() !== x || y.valueOf() !== y) { - // fallback on the objects primitive values - return math.larger(x.valueOf(), y.valueOf()); - } - - throw newUnsupportedTypeError('larger', x, y); + throw new util.error.UnsupportedTypeError('larger', x, y); + }; }; diff --git a/src/function/arithmetic/largereq.js b/src/function/arithmetic/largereq.js index 47d39849f..da721adc5 100644 --- a/src/function/arithmetic/largereq.js +++ b/src/function/arithmetic/largereq.js @@ -1,58 +1,71 @@ -/** - * Check if value x is larger or equal to y - * - * x >= y - * largereq(x, y) - * - * For matrices, the function is evaluated element wise. - * In case of complex numbers, the absolute values of a and b are compared. - * - * @param {Number | Complex | Unit | String | Array | Matrix} x - * @param {Number | Complex | Unit | String | Array | Matrix} y - * @return {Boolean | Array | Matrix} res - */ -math.largereq = function largereq(x, y) { - if (arguments.length != 2) { - throw newArgumentsError('largereq', arguments.length, 2); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (isNumber(x)) { - if (isNumber(y)) { + Complex = require('../../type/Complex.js'), + Unit = require('../../type/Unit.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isString = util.string.isString, + isComplex = Complex.isComplex, + isUnit = Unit.isUnit, + isCollection = collection.isCollection; + + /** + * Check if value x is larger or equal to y + * + * x >= y + * largereq(x, y) + * + * For matrices, the function is evaluated element wise. + * In case of complex numbers, the absolute values of a and b are compared. + * + * @param {Number | Complex | Unit | String | Array | Matrix} x + * @param {Number | Complex | Unit | String | Array | Matrix} y + * @return {Boolean | Array | Matrix} res + */ + math.largereq = function largereq(x, y) { + if (arguments.length != 2) { + throw new util.error.ArgumentsError('largereq', arguments.length, 2); + } + + if (isNumber(x)) { + if (isNumber(y)) { + return x >= y; + } + else if (isComplex(y)) { + return x >= math.abs(y); + } + } + if (isComplex(x)) { + if (isNumber(y)) { + return math.abs(x) >= y; + } + else if (isComplex(y)) { + return math.abs(x) >= math.abs(y); + } + } + + if ((isUnit(x)) && (isUnit(y))) { + if (!x.equalBase(y)) { + throw new Error('Cannot compare units with different base'); + } + return x.value >= y.value; + } + + if (isString(x) || isString(y)) { return x >= y; } - else if (y instanceof Complex) { - return x >= math.abs(y); + + if (isCollection(x) || isCollection(y)) { + return collection.map2(x, y, largereq); } - } - if (x instanceof Complex) { - if (isNumber(y)) { - return math.abs(x) >= y; + + if (x.valueOf() !== x || y.valueOf() !== y) { + // fallback on the objects primitive values + return largereq(x.valueOf(), y.valueOf()); } - else if (y instanceof Complex) { - return math.abs(x) >= math.abs(y); - } - } - if ((x instanceof Unit) && (y instanceof Unit)) { - if (!x.equalBase(y)) { - throw new Error('Cannot compare units with different base'); - } - return x.value >= y.value; - } - - if (isString(x) || isString(y)) { - return x >= y; - } - - if (Array.isArray(x) || x instanceof Matrix || - Array.isArray(y) || y instanceof Matrix) { - return util.map2(x, y, math.largereq); - } - - if (x.valueOf() !== x || y.valueOf() !== y) { - // fallback on the objects primitive values - return math.largereq(x.valueOf(), y.valueOf()); - } - - throw newUnsupportedTypeError('largereq', x, y); + throw new util.error.UnsupportedTypeError('largereq', x, y); + }; }; diff --git a/src/function/arithmetic/lcm.js b/src/function/arithmetic/lcm.js index 8934c7fab..ad885821d 100644 --- a/src/function/arithmetic/lcm.js +++ b/src/function/arithmetic/lcm.js @@ -1,62 +1,71 @@ -/** - * Calculate the least common multiple for two or more values or arrays. - * - * lcm(a, b) - * lcm(a, b, c, ...) - * - * lcm is defined as: - * lcm(a, b) = abs(a * b) / gcd(a, b) - * - * For matrices, the function is evaluated element wise. - * - * @param {... Number | Array | Matrix} args two or more integer numbers - * @return {Number | Array | Matrix} least common multiple - */ -math.lcm = function lcm(args) { - var a = arguments[0], - b = arguments[1], - t; +module.exports = function (math) { + var util = require('../../util/index.js'), - if (arguments.length == 2) { - // two arguments - if (isNumber(a) && isNumber(b)) { - if (!isInteger(a) || !isInteger(b)) { - throw new Error('Parameters in function lcm must be integer numbers'); + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isInteger = util.number.isInteger, + isCollection = collection.isCollection; + + /** + * Calculate the least common multiple for two or more values or arrays. + * + * lcm(a, b) + * lcm(a, b, c, ...) + * + * lcm is defined as: + * lcm(a, b) = abs(a * b) / gcd(a, b) + * + * For matrices, the function is evaluated element wise. + * + * @param {... Number | Array | Matrix} args two or more integer numbers + * @return {Number | Array | Matrix} least common multiple + */ + math.lcm = function lcm(args) { + var a = arguments[0], + b = arguments[1], + t; + + if (arguments.length == 2) { + // two arguments + if (isNumber(a) && isNumber(b)) { + if (!isInteger(a) || !isInteger(b)) { + throw new Error('Parameters in function lcm must be integer numbers'); + } + + // http://en.wikipedia.org/wiki/Euclidean_algorithm + // evaluate gcd here inline to reduce overhead + var prod = a * b; + while (b != 0) { + t = b; + b = a % t; + a = t; + } + return Math.abs(prod / a); } - // http://en.wikipedia.org/wiki/Euclidean_algorithm - // evaluate gcd here inline to reduce overhead - var prod = a * b; - while (b != 0) { - t = b; - b = a % t; - a = t; + // evaluate lcm element wise + if (isCollection(a) || isCollection(b)) { + return collection.map2(a, b, lcm); } - return Math.abs(prod / a); + + if (a.valueOf() !== a || b.valueOf() !== b) { + // fallback on the objects primitive value + return lcm(a.valueOf(), b.valueOf()); + } + + throw new util.error.UnsupportedTypeError('lcm', a, b); } - // evaluate lcm element wise - if (Array.isArray(a) || a instanceof Matrix || - Array.isArray(b) || b instanceof Matrix) { - return util.map2(a, b, math.lcm); + if (arguments.length > 2) { + // multiple arguments. Evaluate them iteratively + for (var i = 1; i < arguments.length; i++) { + a = lcm(a, arguments[i]); + } + return a; } - if (a.valueOf() !== a || b.valueOf() !== b) { - // fallback on the objects primitive value - return math.lcm(a.valueOf(), b.valueOf()); - } - - throw newUnsupportedTypeError('lcm', a, b); - } - - if (arguments.length > 2) { - // multiple arguments. Evaluate them iteratively - for (var i = 1; i < arguments.length; i++) { - a = math.lcm(a, arguments[i]); - } - return a; - } - - // zero or one argument - throw new SyntaxError('Function lcm expects two or more arguments'); + // zero or one argument + throw new SyntaxError('Function lcm expects two or more arguments'); + }; }; diff --git a/src/function/arithmetic/log.js b/src/function/arithmetic/log.js index a683bbc5b..0f9c0e2ab 100644 --- a/src/function/arithmetic/log.js +++ b/src/function/arithmetic/log.js @@ -1,52 +1,63 @@ -/** - * Calculate the logarithm of a value - * - * log(x) - * log(x, base) - * - * base is optional. If not provided, the natural logarithm of x is calculated. - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @param {Number | Complex} [base] - * @return {Number | Complex | Array | Matrix} res - */ -math.log = function log(x, base) { - if (arguments.length == 1) { - // calculate natural logarithm, log(x) - if (isNumber(x)) { - if (x >= 0) { - return Math.log(x); +module.exports = function (math) { + var util = require('../../util/index.js'), + + Complex = require('../../type/Complex.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isCollection = collection.isCollection; + + /** + * Calculate the logarithm of a value + * + * log(x) + * log(x, base) + * + * base is optional. If not provided, the natural logarithm of x is calculated. + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} x + * @param {Number | Complex} [base] + * @return {Number | Complex | Array | Matrix} res + */ + math.log = function log(x, base) { + if (arguments.length == 1) { + // calculate natural logarithm, log(x) + if (isNumber(x)) { + if (x >= 0) { + return Math.log(x); + } + else { + // negative value -> complex value computation + return log(new Complex(x, 0)); + } } - else { - // negative value -> complex value computation - return math.log(new Complex(x, 0)); + + if (isComplex(x)) { + return Complex.create ( + Math.log(Math.sqrt(x.re * x.re + x.im * x.im)), + Math.atan2(x.im, x.re) + ); } - } - if (x instanceof Complex) { - return Complex.create ( - Math.log(Math.sqrt(x.re * x.re + x.im * x.im)), - Math.atan2(x.im, x.re) - ); - } + if (isCollection(x)) { + return collection.map(x, log); + } - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.log); - } + if (x.valueOf() !== x) { + // fallback on the objects primitive values + return log(x.valueOf()); + } - if (x.valueOf() !== x) { - // fallback on the objects primitive values - return math.log(x.valueOf()); + throw new util.error.UnsupportedTypeError('log', x); } - - throw newUnsupportedTypeError('log', x); - } - else if (arguments.length == 2) { - // calculate logarithm for a specified base, log(x, base) - return math.divide(math.log(x), math.log(base)); - } - else { - throw newArgumentsError('log', arguments.length, 1, 2); - } + else if (arguments.length == 2) { + // calculate logarithm for a specified base, log(x, base) + return math.divide(log(x), log(base)); + } + else { + throw new util.error.ArgumentsError('log', arguments.length, 1, 2); + } + }; }; diff --git a/src/function/arithmetic/log10.js b/src/function/arithmetic/log10.js index 87b2350aa..c4a7a8633 100644 --- a/src/function/arithmetic/log10.js +++ b/src/function/arithmetic/log10.js @@ -1,43 +1,54 @@ -/** - * Calculate the 10-base logarithm of a value - * - * log10(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ -math.log10 = function log10(x) { - if (arguments.length != 1) { - throw newArgumentsError('log10', arguments.length, 1); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (isNumber(x)) { - if (x >= 0) { - return Math.log(x) / Math.LN10; + Complex = require('../../type/Complex.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isCollection = collection.isCollection; + + /** + * Calculate the 10-base logarithm of a value + * + * log10(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + */ + math.log10 = function log10(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('log10', arguments.length, 1); } - else { - // negative value -> complex value computation - return math.log10(new Complex(x, 0)); + + if (isNumber(x)) { + if (x >= 0) { + return Math.log(x) / Math.LN10; + } + else { + // negative value -> complex value computation + return log10(new Complex(x, 0)); + } } - } - if (x instanceof Complex) { - return Complex.create ( - Math.log(Math.sqrt(x.re * x.re + x.im * x.im)) / Math.LN10, - Math.atan2(x.im, x.re) / Math.LN10 - ); - } + if (isComplex(x)) { + return Complex.create ( + Math.log(Math.sqrt(x.re * x.re + x.im * x.im)) / Math.LN10, + Math.atan2(x.im, x.re) / Math.LN10 + ); + } - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.log10); - } + if (isCollection(x)) { + return collection.map(x, log10); + } - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.log10(x.valueOf()); - } + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return log10(x.valueOf()); + } - throw newUnsupportedTypeError('log10', x); + throw new util.error.UnsupportedTypeError('log10', x); + }; }; diff --git a/src/function/arithmetic/mod.js b/src/function/arithmetic/mod.js index 9ccb43594..7cd64a090 100644 --- a/src/function/arithmetic/mod.js +++ b/src/function/arithmetic/mod.js @@ -1,66 +1,74 @@ -/** - * Calculates the modulus, the remainder of an integer division. - * - * x % y - * mod(x, y) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @param {Number | Complex | Array | Matrix} y - * @return {Number | Array | Matrix} res - */ -math.mod = function mod(x, y) { - if (arguments.length != 2) { - throw newArgumentsError('mod', arguments.length, 2); +module.exports = function (math) { + var util = require('../../util/index.js'), + + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isCollection = collection.isCollection; + + /** + * Calculates the modulus, the remainder of an integer division. + * + * x % y + * mod(x, y) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Array | Matrix} x + * @param {Number | Array | Matrix} y + * @return {Number | Array | Matrix} res + */ + math.mod = function mod(x, y) { + if (arguments.length != 2) { + throw new util.error.ArgumentsError('mod', arguments.length, 2); + } + + // see http://functions.wolfram.com/IntegerFunctions/Mod/ + + if (isNumber(x) && isNumber(y)) { + // number % number + return _mod(x, y); + } + + // TODO: implement mod for complex values + + if (isCollection(x) || isCollection(y)) { + return collection.map2(x, y, mod); + } + + if (x.valueOf() !== x || y.valueOf() !== y) { + // fallback on the objects primitive values + return mod(x.valueOf(), y.valueOf()); + } + + throw new util.error.UnsupportedTypeError('mod', x, y); + }; + + /** + * Calculate the modulus of two numbers + * @param {Number} x + * @param {Number} y + * @returns {number} res + * @private + */ + function _mod(x, y) { + if (y > 0) { + if (x > 0) { + return x % y; + } + else if (x == 0) { + return 0; + } + else { // x < 0 + return x - y * Math.floor(x / y); + } + } + else if (y == 0) { + return x; + } + else { // y < 0 + // TODO: implement mod for a negative divisor + throw new Error('Cannot calculate mod for a negative divisor'); + } } - - // see http://functions.wolfram.com/IntegerFunctions/Mod/ - - if (isNumber(x) && isNumber(y)) { - // number % number - return _mod(x, y); - } - - // TODO: implement mod for complex values - - if (Array.isArray(x) || x instanceof Matrix || - Array.isArray(y) || y instanceof Matrix) { - return util.map2(x, y, math.mod); - } - - if (x.valueOf() !== x || y.valueOf() !== y) { - // fallback on the objects primitive values - return math.mod(x.valueOf(), y.valueOf()); - } - - throw newUnsupportedTypeError('mod', x, y); }; - -/** - * Calculate the modulus of two numbers - * @param {Number} x - * @param {Number} y - * @returns {number} res - * @private - */ -function _mod(x, y) { - if (y > 0) { - if (x > 0) { - return x % y; - } - else if (x == 0) { - return 0; - } - else { // x < 0 - return x - y * Math.floor(x / y); - } - } - else if (y == 0) { - return x; - } - else { // y < 0 - // TODO: implement mod for a negative divisor - throw new Error('Cannot calculate mod for a negative divisor'); - } -} \ No newline at end of file diff --git a/src/function/arithmetic/multiply.js b/src/function/arithmetic/multiply.js index e38d2c21d..2fc270cf4 100644 --- a/src/function/arithmetic/multiply.js +++ b/src/function/arithmetic/multiply.js @@ -1,197 +1,210 @@ -/** - * Multiply two values. - * - * x * y - * multiply(x, y) - * - * @param {Number | Complex | Unit | Array | Matrix} x - * @param {Number | Complex | Unit | Array | Matrix} y - * @return {Number | Complex | Unit | Array | Matrix} res - */ -math.multiply = function multiply(x, y) { - if (arguments.length != 2) { - throw newArgumentsError('multiply', arguments.length, 2); - } +module.exports = function(math) { + var util = require('../../util/index.js'), - if (isNumber(x)) { - if (isNumber(y)) { - // number * number - return x * y; - } - else if (y instanceof Complex) { - // number * complex - return _multiplyComplex (new Complex(x, 0), y); - } - else if (y instanceof Unit) { - res = y.clone(); - res.value *= x; - return res; - } - } - else if (x instanceof Complex) { - if (isNumber(y)) { - // complex * number - return _multiplyComplex (x, new Complex(y, 0)); - } - else if (y instanceof Complex) { - // complex * complex - return _multiplyComplex (x, y); - } - } - else if (x instanceof Unit) { - if (isNumber(y)) { - res = x.clone(); - res.value *= y; - return res; - } - } - else if (Array.isArray(x)) { - if (Array.isArray(y)) { - // matrix * matrix - var sizeX = util.size(x); - var sizeY = util.size(y); + Complex = require('../../type/Complex.js'), + Matrix = require('../../type/Matrix.js'), + Unit = require('../../type/Unit.js'), + collection = require('../../type/collection.js'), - if (sizeX.length != 2) { - throw new Error('Can only multiply a 2 dimensional matrix ' + - '(A has ' + sizeX.length + ' dimensions)'); - } - if (sizeY.length != 2) { - throw new Error('Can only multiply a 2 dimensional matrix ' + - '(B has ' + sizeY.length + ' dimensions)'); - } - if (sizeX[1] != sizeY[0]) { - throw new RangeError('Dimensions mismatch in multiplication. ' + - 'Columns of A must match rows of B ' + - '(A is ' + sizeX[0] + 'x' + sizeX[1] + - ', B is ' + sizeY[0] + 'x' + sizeY[1] + ', ' + - sizeY[1] + ' != ' + sizeY[0] + ')'); - } + array = util.array, + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isArray = Array.isArray, + isUnit = Unit.isUnit; - // TODO: performance of matrix multiplication can be improved - var res = [], - rows = sizeX[0], - cols = sizeY[1], - num = sizeX[1], - multiply = math.multiply, - add = math.add; - for (var r = 0; r < rows; r++) { - res[r] = []; - for (var c = 0; c < cols; c++) { - var result = null; - for (var n = 0; n < num; n++) { - var p = multiply(x[r][n], y[n][c]); - result = (result == null) ? p : add(result, p); - } - res[r][c] = result; + /** + * Multiply two values. + * + * x * y + * multiply(x, y) + * + * @param {Number | Complex | Unit | Array | Matrix} x + * @param {Number | Complex | Unit | Array | Matrix} y + * @return {Number | Complex | Unit | Array | Matrix} res + */ + math.multiply = function multiply(x, y) { + if (arguments.length != 2) { + throw new util.error.ArgumentsError('multiply', arguments.length, 2); + } + + if (isNumber(x)) { + if (isNumber(y)) { + // number * number + return x * y; + } + else if (isComplex(y)) { + // number * complex + return _multiplyComplex (new Complex(x, 0), y); + } + else if (isUnit(y)) { + res = y.clone(); + res.value *= x; + return res; + } + } + else if (isComplex(x)) { + if (isNumber(y)) { + // complex * number + return _multiplyComplex (x, new Complex(y, 0)); + } + else if (isComplex(y)) { + // complex * complex + return _multiplyComplex (x, y); + } + } + else if (isUnit(x)) { + if (isNumber(y)) { + res = x.clone(); + res.value *= y; + return res; + } + } + else if (isArray(x)) { + if (isArray(y)) { + // matrix * matrix + var sizeX = array.size(x); + var sizeY = array.size(y); + + if (sizeX.length != 2) { + throw new Error('Can only multiply a 2 dimensional matrix ' + + '(A has ' + sizeX.length + ' dimensions)'); + } + if (sizeY.length != 2) { + throw new Error('Can only multiply a 2 dimensional matrix ' + + '(B has ' + sizeY.length + ' dimensions)'); + } + if (sizeX[1] != sizeY[0]) { + throw new RangeError('Dimensions mismatch in multiplication. ' + + 'Columns of A must match rows of B ' + + '(A is ' + sizeX[0] + 'x' + sizeX[1] + + ', B is ' + sizeY[0] + 'x' + sizeY[1] + ', ' + + sizeY[1] + ' != ' + sizeY[0] + ')'); } - } - return res; + // TODO: performance of matrix multiplication can be improved + var res = [], + rows = sizeX[0], + cols = sizeY[1], + num = sizeX[1]; + for (var r = 0; r < rows; r++) { + res[r] = []; + for (var c = 0; c < cols; c++) { + var result = null; + for (var n = 0; n < num; n++) { + var p = multiply(x[r][n], y[n][c]); + result = (result == null) ? p : math.add(result, p); + } + res[r][c] = result; + } + } + + return res; + } + else if (y instanceof Matrix) { + return new Matrix(multiply(x.valueOf(), y.valueOf())); + } + else { + // matrix * scalar + return collection.map2(x, y, multiply); + } + } + else if (x instanceof Matrix) { + return new Matrix(multiply(x.valueOf(), y.valueOf())); + } + + if (isArray(y)) { + // scalar * matrix + return collection.map2(x, y, multiply); } else if (y instanceof Matrix) { - return new Matrix(math.multiply(x.valueOf(), y.valueOf())); + return new Matrix(multiply(x.valueOf(), y.valueOf())); + } + + if (x.valueOf() !== x || y.valueOf() !== y) { + // fallback on the objects primitive values + return multiply(x.valueOf(), y.valueOf()); + } + + throw new util.error.UnsupportedTypeError('multiply', x, y); + }; + + /** + * Multiply two complex numbers. x * y or multiply(x, y) + * @param {Complex} x + * @param {Complex} y + * @return {Complex | Number} res + * @private + */ + function _multiplyComplex (x, y) { + // Note: we test whether x or y are pure real or pure complex, + // to prevent unnecessary NaN values. For example, Infinity*i should + // result in Infinity*i, and not in NaN+Infinity*i + + if (x.im == 0) { + // x is pure real + if (y.im == 0) { + // y is pure real + return x.re * y.re; + } + else if (y.re == 0) { + // y is pure complex + return new Complex( + 0, + x.re * y.im + ); + } + else { + // y has a real and complex part + return new Complex( + x.re * y.re, + x.re * y.im + ); + } + } + else if (x.re == 0) { + // x is pure complex + if (y.im == 0) { + // y is pure real + return new Complex( + 0, + x.im * y.re + ); + } + else if (y.re == 0) { + // y is pure complex + return -x.im * y.im; + } + else { + // y has a real and complex part + return new Complex( + -x.im * y.im, + x.im * y.re + ); + } } else { - // matrix * scalar - return util.map2(x, y, math.multiply); + // x has a real and complex part + if (y.im == 0) { + // y is pure real + return new Complex( + x.re * y.re, + x.im * y.re + ); + } + else if (y.re == 0) { + // y is pure complex + return new Complex( + -x.im * y.im, + x.re * y.im + ); + } + else { + // y has a real and complex part + return new Complex( + x.re * y.re - x.im * y.im, + x.re * y.im + x.im * y.re + ); + } } } - else if (x instanceof Matrix) { - return new Matrix(math.multiply(x.valueOf(), y.valueOf())); - } - - if (Array.isArray(y)) { - // scalar * matrix - return util.map2(x, y, math.multiply); - } - else if (y instanceof Matrix) { - return new Matrix(math.multiply(x.valueOf(), y.valueOf())); - } - - if (x.valueOf() !== x || y.valueOf() !== y) { - // fallback on the objects primitive values - return math.multiply(x.valueOf(), y.valueOf()); - } - - throw newUnsupportedTypeError('multiply', x, y); }; - -/** - * Multiply two complex numbers. x * y or multiply(x, y) - * @param {Complex} x - * @param {Complex} y - * @return {Complex | Number} res - * @private - */ -function _multiplyComplex (x, y) { - // Note: we test whether x or y are pure real or pure complex, - // to prevent unnecessary NaN values. For example, Infinity*i should - // result in Infinity*i, and not in NaN+Infinity*i - - if (x.im == 0) { - // x is pure real - if (y.im == 0) { - // y is pure real - return x.re * y.re; - } - else if (y.re == 0) { - // y is pure complex - return new Complex( - 0, - x.re * y.im - ); - } - else { - // y has a real and complex part - return new Complex( - x.re * y.re, - x.re * y.im - ); - } - } - else if (x.re == 0) { - // x is pure complex - if (y.im == 0) { - // y is pure real - return new Complex( - 0, - x.im * y.re - ); - } - else if (y.re == 0) { - // y is pure complex - return -x.im * y.im; - } - else { - // y has a real and complex part - return new Complex( - -x.im * y.im, - x.im * y.re - ); - } - } - else { - // x has a real and complex part - if (y.im == 0) { - // y is pure real - return new Complex( - x.re * y.re, - x.im * y.re - ); - } - else if (y.re == 0) { - // y is pure complex - return new Complex( - -x.im * y.im, - x.re * y.im - ); - } - else { - // y has a real and complex part - return new Complex( - x.re * y.re - x.im * y.im, - x.re * y.im + x.im * y.re - ); - } - } -} diff --git a/src/function/arithmetic/pow.js b/src/function/arithmetic/pow.js index 3846a4bc7..d045d19b4 100644 --- a/src/function/arithmetic/pow.js +++ b/src/function/arithmetic/pow.js @@ -1,92 +1,105 @@ -/** - * Calculates the power of x to y - * - * x ^ y - * pow(x, y) - * - * @param {Number | Complex | Array | Matrix} x - * @param {Number | Complex} y - * @return {Number | Complex | Array | Matrix} res - */ -math.pow = function pow(x, y) { - if (arguments.length != 2) { - throw newArgumentsError('pow', arguments.length, 2); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (isNumber(x)) { - if (isNumber(y)) { - if (isInteger(y) || x >= 0) { - // real value computation - return Math.pow(x, y); + Complex = require('../../type/Complex.js'), + Matrix = require('../../type/Matrix.js'), + + array = util.array, + isNumber = util.number.isNumber, + isArray = Array.isArray, + isInteger = util.number.isInteger, + isComplex = Complex.isComplex; + + /** + * Calculates the power of x to y + * + * x ^ y + * pow(x, y) + * + * @param {Number | Complex | Array | Matrix} x + * @param {Number | Complex} y + * @return {Number | Complex | Array | Matrix} res + */ + math.pow = function pow(x, y) { + if (arguments.length != 2) { + throw new util.error.ArgumentsError('pow', arguments.length, 2); + } + + if (isNumber(x)) { + if (isNumber(y)) { + if (isInteger(y) || x >= 0) { + // real value computation + return Math.pow(x, y); + } + else { + return powComplex(new Complex(x, 0), new Complex(y, 0)); + } + } + else if (isComplex(y)) { + return powComplex(new Complex(x, 0), y); + } + } + else if (isComplex(x)) { + if (isNumber(y)) { + return powComplex(x, new Complex(y, 0)); + } + else if (isComplex(y)) { + return powComplex(x, y); + } + } + else if (isArray(x)) { + if (!isNumber(y) || !isInteger(y) || y < 0) { + throw new TypeError('For A^b, b must be a positive integer ' + + '(value is ' + y + ')'); + } + // verify that A is a 2 dimensional square matrix + var s = array.size(x); + if (s.length != 2) { + throw new Error('For A^b, A must be 2 dimensional ' + + '(A has ' + s.length + ' dimensions)'); + } + if (s[0] != s[1]) { + throw new Error('For A^b, A must be square ' + + '(size is ' + s[0] + 'x' + s[1] + ')'); + } + + if (y == 0) { + // return the identity matrix + return math.eye(s[0]); } else { - return powComplex(new Complex(x, 0), new Complex(y, 0)); + // value > 0 + var res = x; + for (var i = 1; i < y; i++) { + res = math.multiply(x, res); + } + return res; } } - else if (y instanceof Complex) { - return powComplex(new Complex(x, 0), y); - } - } - else if (x instanceof Complex) { - if (isNumber(y)) { - return powComplex(x, new Complex(y, 0)); - } - else if (y instanceof Complex) { - return powComplex(x, y); - } - } - else if (Array.isArray(x)) { - if (!isNumber(y) || !isInteger(y) || y < 0) { - throw new TypeError('For A^b, b must be a positive integer ' + - '(value is ' + y + ')'); - } - // verify that A is a 2 dimensional square matrix - var s = util.size(x); - if (s.length != 2) { - throw new Error('For A^b, A must be 2 dimensional ' + - '(A has ' + s.length + ' dimensions)'); - } - if (s[0] != s[1]) { - throw new Error('For A^b, A must be square ' + - '(size is ' + s[0] + 'x' + s[1] + ')'); + else if (x instanceof Matrix) { + return new Matrix(pow(x.valueOf(), y)); } - if (y == 0) { - // return the identity matrix - return math.eye(s[0]); + if (x.valueOf() !== x || y.valueOf() !== y) { + // fallback on the objects primitive values + return pow(x.valueOf(), y.valueOf()); } - else { - // value > 0 - var res = x; - for (var i = 1; i < y; i++) { - res = math.multiply(x, res); - } - return res; - } - } - else if (x instanceof Matrix) { - return new Matrix(math.pow(x.valueOf(), y)); - } - if (x.valueOf() !== x || y.valueOf() !== y) { - // fallback on the objects primitive values - return math.pow(x.valueOf(), y.valueOf()); - } + throw new util.error.UnsupportedTypeError('pow', x, y); + }; - throw newUnsupportedTypeError('pow', x, y); + /** + * Calculates the power of x to y, x^y, for two complex numbers. + * @param {Complex} x + * @param {Complex} y + * @return {Complex} res + * @private + */ + function powComplex (x, y) { + // complex computation + // x^y = exp(log(x)*y) = exp((abs(x)+i*arg(x))*y) + var temp1 = math.log(x); + var temp2 = math.multiply(temp1, y); + return math.exp(temp2); + } }; - -/** - * Calculates the power of x to y, x^y, for two complex numbers. - * @param {Complex} x - * @param {Complex} y - * @return {Complex} res - * @private - */ -function powComplex (x, y) { - // complex computation - // x^y = exp(log(x)*y) = exp((abs(x)+i*arg(x))*y) - var temp1 = math.log(x); - var temp2 = math.multiply(temp1, y); - return math.exp(temp2); -} diff --git a/src/function/arithmetic/round.js b/src/function/arithmetic/round.js index 9a13ad49f..aba4759c0 100644 --- a/src/function/arithmetic/round.js +++ b/src/function/arithmetic/round.js @@ -1,94 +1,104 @@ -/** - * Round a value towards the nearest integer - * - * round(x) - * round(x, n) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @param {Number | Array} [n] number of decimals (by default n=0) - * @return {Number | Complex | Array | Matrix} res - */ -math.round = function round(x, n) { - if (arguments.length != 1 && arguments.length != 2) { - throw newArgumentsError('round', arguments.length, 1, 2); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (n == undefined) { - // round (x) - if (isNumber(x)) { - return Math.round(x); + Complex = require('../../type/Complex.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isCollection = collection.isCollection; + + /** + * Round a value towards the nearest integer + * + * round(x) + * round(x, n) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} x + * @param {Number | Array} [n] number of decimals (by default n=0) + * @return {Number | Complex | Array | Matrix} res + */ + math.round = function round(x, n) { + if (arguments.length != 1 && arguments.length != 2) { + throw new util.error.ArgumentsError('round', arguments.length, 1, 2); } - if (x instanceof Complex) { - return Complex.create ( - Math.round(x.re), - Math.round(x.im) - ); - } + if (n == undefined) { + // round (x) + if (isNumber(x)) { + return Math.round(x); + } - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.round); - } + if (isComplex(x)) { + return Complex.create ( + Math.round(x.re), + Math.round(x.im) + ); + } - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.round(x.valueOf()); - } + if (isCollection(x)) { + return collection.map(x, round); + } - throw newUnsupportedTypeError('round', x); - } - else { - // round (x, n) - if (!isNumber(n)) { - throw new TypeError('Number of decimals in function round must be an integer'); - } - if (n !== Math.round(n)) { - throw new TypeError('Number of decimals in function round must be integer'); - } - if (n < 0 || n > 9) { - throw new Error ('Number of decimals in function round must be in te range of 0-9'); - } + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return round(x.valueOf()); + } - if (isNumber(x)) { - return roundNumber(x, n); + throw new util.error.UnsupportedTypeError('round', x); } + else { + // round (x, n) + if (!isNumber(n)) { + throw new TypeError('Number of decimals in function round must be an integer'); + } + if (n !== Math.round(n)) { + throw new TypeError('Number of decimals in function round must be integer'); + } + if (n < 0 || n > 9) { + throw new Error ('Number of decimals in function round must be in te range of 0-9'); + } - if (x instanceof Complex) { - return Complex.create ( - roundNumber(x.re, n), - roundNumber(x.im, n) - ); + if (isNumber(x)) { + return roundNumber(x, n); + } + + if (isComplex(x)) { + return Complex.create ( + roundNumber(x.re, n), + roundNumber(x.im, n) + ); + } + + if (isCollection(x) || isCollection(n)) { + return collection.map2(x, n, round); + } + + if (x.valueOf() !== x || n.valueOf() !== n) { + // fallback on the objects primitive values + return round(x.valueOf(), n.valueOf()); + } + + throw new util.error.UnsupportedTypeError('round', x, n); } + }; - if (Array.isArray(x) || x instanceof Matrix || - Array.isArray(n) || n instanceof Matrix) { - return util.map2(x, n, math.round); + /** + * round a number to the given number of decimals, or to zero if decimals is + * not provided + * @param {Number} value + * @param {Number} [decimals] number of decimals, between 0 and 15 (0 by default) + * @return {Number} roundedValue + */ + function roundNumber (value, decimals) { + if (decimals) { + var p = Math.pow(10, decimals); + return Math.round(value * p) / p; } - - if (x.valueOf() !== x || n.valueOf() !== n) { - // fallback on the objects primitive values - return math.round(x.valueOf(), n.valueOf()); + else { + return Math.round(value); } - - throw newUnsupportedTypeError('round', x, n); } }; - -/** - * round a number to the given number of decimals, or to zero if decimals is - * not provided - * @param {Number} value - * @param {Number} [decimals] number of decimals, between 0 and 15 (0 by default) - * @return {Number} roundedValue - */ -function roundNumber (value, decimals) { - if (decimals) { - var p = Math.pow(10, decimals); - return Math.round(value * p) / p; - } - else { - return Math.round(value); - } -} diff --git a/src/function/arithmetic/sign.js b/src/function/arithmetic/sign.js index 40cc75ee9..d2630eb72 100644 --- a/src/function/arithmetic/sign.js +++ b/src/function/arithmetic/sign.js @@ -1,46 +1,48 @@ -/** - * Compute the sign of a value. - * - * sign(x) - * - * The sign of a value x is 1 when x > 1, -1 when x < 0, and 0 when x == 0 - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ -math.sign = function sign(x) { - if (arguments.length != 1) { - throw newArgumentsError('sign', arguments.length, 1); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (isNumber(x)) { - var sign; - if (x > 0) { - sign = 1; + Complex = require('../../type/Complex.js'), + collection = require('../../type/collection.js'), + + number = util.number, + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isCollection = collection.isCollection; + + /** + * Compute the sign of a value. + * + * sign(x) + * + * The sign of a value x is 1 when x > 1, -1 when x < 0, and 0 when x == 0 + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + */ + math.sign = function sign(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('sign', arguments.length, 1); } - else if (x < 0) { - sign = -1; + + if (isNumber(x)) { + return number.sign(x); } - else { - sign = 0; + + if (isComplex(x)) { + var abs = Math.sqrt(x.re * x.re + x.im * x.im); + return Complex.create(x.re / abs, x.im / abs); } - return sign; - } - if (x instanceof Complex) { - var abs = Math.sqrt(x.re * x.re + x.im * x.im); - return Complex.create(x.re / abs, x.im / abs); - } + if (isCollection(x)) { + return collection.map(x, sign); + } - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.sign); - } + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return sign(x.valueOf()); + } - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.sign(x.valueOf()); - } - - throw newUnsupportedTypeError('sign', x); + throw new util.error.UnsupportedTypeError('sign', x); + }; }; diff --git a/src/function/arithmetic/smaller.js b/src/function/arithmetic/smaller.js index 74d5db8f3..76143cf70 100644 --- a/src/function/arithmetic/smaller.js +++ b/src/function/arithmetic/smaller.js @@ -1,58 +1,71 @@ -/** - * Check if value x is smaller y - * - * x < y - * smaller(x, y) - * - * For matrices, the function is evaluated element wise. - * In case of complex numbers, the absolute values of a and b are compared. - * - * @param {Number | Complex | Unit | String | Array | Matrix} x - * @param {Number | Complex | Unit | String | Array | Matrix} y - * @return {Boolean | Array | Matrix} res - */ -math.smaller = function smaller(x, y) { - if (arguments.length != 2) { - throw newArgumentsError('smaller', arguments.length, 2); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (isNumber(x)) { - if (isNumber(y)) { + Complex = require('../../type/Complex.js'), + Unit = require('../../type/Unit.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isString = util.string.isString, + isComplex = Complex.isComplex, + isUnit = Unit.isUnit, + isCollection = collection.isCollection; + + /** + * Check if value x is smaller y + * + * x < y + * smaller(x, y) + * + * For matrices, the function is evaluated element wise. + * In case of complex numbers, the absolute values of a and b are compared. + * + * @param {Number | Complex | Unit | String | Array | Matrix} x + * @param {Number | Complex | Unit | String | Array | Matrix} y + * @return {Boolean | Array | Matrix} res + */ + math.smaller = function smaller(x, y) { + if (arguments.length != 2) { + throw new util.error.ArgumentsError('smaller', arguments.length, 2); + } + + if (isNumber(x)) { + if (isNumber(y)) { + return x < y; + } + else if (isComplex(y)) { + return x < math.abs(y); + } + } + if (isComplex(x)) { + if (isNumber(y)) { + return math.abs(x) < y; + } + else if (isComplex(y)) { + return math.abs(x) < math.abs(y); + } + } + + if ((isUnit(x)) && (isUnit(y))) { + if (!x.equalBase(y)) { + throw new Error('Cannot compare units with different base'); + } + return x.value < y.value; + } + + if (isString(x) || isString(y)) { return x < y; } - else if (y instanceof Complex) { - return x < math.abs(y); + + if (isCollection(x) || isCollection(y)) { + return collection.map2(x, y, smaller); } - } - if (x instanceof Complex) { - if (isNumber(y)) { - return math.abs(x) < y; + + if (x.valueOf() !== x || y.valueOf() !== y) { + // fallback on the objects primitive values + return smaller(x.valueOf(), y.valueOf()); } - else if (y instanceof Complex) { - return math.abs(x) < math.abs(y); - } - } - if ((x instanceof Unit) && (y instanceof Unit)) { - if (!x.equalBase(y)) { - throw new Error('Cannot compare units with different base'); - } - return x.value < y.value; - } - - if (isString(x) || isString(y)) { - return x < y; - } - - if (Array.isArray(x) || x instanceof Matrix || - Array.isArray(y) || y instanceof Matrix) { - return util.map2(x, y, math.smaller); - } - - if (x.valueOf() !== x || y.valueOf() !== y) { - // fallback on the objects primitive values - return math.smaller(x.valueOf(), y.valueOf()); - } - - throw newUnsupportedTypeError('smaller', x, y); + throw new util.error.UnsupportedTypeError('smaller', x, y); + }; }; diff --git a/src/function/arithmetic/smallereq.js b/src/function/arithmetic/smallereq.js index 5339d7fd1..c45f3e6ce 100644 --- a/src/function/arithmetic/smallereq.js +++ b/src/function/arithmetic/smallereq.js @@ -1,58 +1,71 @@ -/** - * Check if value a is smaller or equal to b - * - * a <= b - * smallereq(a, b) - * - * For matrices, the function is evaluated element wise. - * In case of complex numbers, the absolute values of a and b are compared. - * - * @param {Number | Complex | Unit | String | Array | Matrix} x - * @param {Number | Complex | Unit | String | Array | Matrix} y - * @return {Boolean | Array | Matrix} res - */ -math.smallereq = function smallereq(x, y) { - if (arguments.length != 2) { - throw newArgumentsError('smallereq', arguments.length, 2); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (isNumber(x)) { - if (isNumber(y)) { + Complex = require('../../type/Complex.js'), + Unit = require('../../type/Unit.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isString = util.string.isString, + isComplex = Complex.isComplex, + isUnit = Unit.isUnit, + isCollection = collection.isCollection; + + /** + * Check if value a is smaller or equal to b + * + * a <= b + * smallereq(a, b) + * + * For matrices, the function is evaluated element wise. + * In case of complex numbers, the absolute values of a and b are compared. + * + * @param {Number | Complex | Unit | String | Array | Matrix} x + * @param {Number | Complex | Unit | String | Array | Matrix} y + * @return {Boolean | Array | Matrix} res + */ + math.smallereq = function smallereq(x, y) { + if (arguments.length != 2) { + throw new util.error.ArgumentsError('smallereq', arguments.length, 2); + } + + if (isNumber(x)) { + if (isNumber(y)) { + return x <= y; + } + else if (isComplex(y)) { + return x <= math.abs(y); + } + } + if (isComplex(x)) { + if (isNumber(y)) { + return math.abs(x) <= y; + } + else if (isComplex(y)) { + return math.abs(x) <= math.abs(y); + } + } + + if ((isUnit(x)) && (isUnit(y))) { + if (!x.equalBase(y)) { + throw new Error('Cannot compare units with different base'); + } + return x.value <= y.value; + } + + if (isString(x) || isString(y)) { return x <= y; } - else if (y instanceof Complex) { - return x <= math.abs(y); + + if (isCollection(x) || isCollection(y)) { + return collection.map2(x, y, smallereq); } - } - if (x instanceof Complex) { - if (isNumber(y)) { - return math.abs(x) <= y; + + if (x.valueOf() !== x || y.valueOf() !== y) { + // fallback on the objects primitive values + return smallereq(x.valueOf(), y.valueOf()); } - else if (y instanceof Complex) { - return math.abs(x) <= math.abs(y); - } - } - if ((x instanceof Unit) && (y instanceof Unit)) { - if (!x.equalBase(y)) { - throw new Error('Cannot compare units with different base'); - } - return x.value <= y.value; - } - - if (isString(x) || isString(y)) { - return x <= y; - } - - if (Array.isArray(x) || x instanceof Matrix || - Array.isArray(y) || y instanceof Matrix) { - return util.map2(x, y, math.smallereq); - } - - if (x.valueOf() !== x || y.valueOf() !== y) { - // fallback on the objects primitive values - return math.smallereq(x.valueOf(), y.valueOf()); - } - - throw newUnsupportedTypeError('smallereq', x, y); + throw new util.error.UnsupportedTypeError('smallereq', x, y); + }; }; diff --git a/src/function/arithmetic/sqrt.js b/src/function/arithmetic/sqrt.js index aeb671500..b3448fcae 100644 --- a/src/function/arithmetic/sqrt.js +++ b/src/function/arithmetic/sqrt.js @@ -1,51 +1,62 @@ -/** - * Calculate the square root of a value - * - * sqrt(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ -math.sqrt = function sqrt (x) { - if (arguments.length != 1) { - throw newArgumentsError('sqrt', arguments.length, 1); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (isNumber(x)) { - if (x >= 0) { - return Math.sqrt(x); + Complex = require('../../type/Complex.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isCollection = collection.isCollection; + + /** + * Calculate the square root of a value + * + * sqrt(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + */ + math.sqrt = function sqrt (x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('sqrt', arguments.length, 1); } - else { - return math.sqrt(new Complex(x, 0)); + + if (isNumber(x)) { + if (x >= 0) { + return Math.sqrt(x); + } + else { + return sqrt(new Complex(x, 0)); + } } - } - if (x instanceof Complex) { - var r = Math.sqrt(x.re * x.re + x.im * x.im); - if (x.im >= 0) { - return Complex.create( - 0.5 * Math.sqrt(2.0 * (r + x.re)), - 0.5 * Math.sqrt(2.0 * (r - x.re)) - ); + if (isComplex(x)) { + var r = Math.sqrt(x.re * x.re + x.im * x.im); + if (x.im >= 0) { + return Complex.create( + 0.5 * Math.sqrt(2.0 * (r + x.re)), + 0.5 * Math.sqrt(2.0 * (r - x.re)) + ); + } + else { + return Complex.create( + 0.5 * Math.sqrt(2.0 * (r + x.re)), + -0.5 * Math.sqrt(2.0 * (r - x.re)) + ); + } } - else { - return Complex.create( - 0.5 * Math.sqrt(2.0 * (r + x.re)), - -0.5 * Math.sqrt(2.0 * (r - x.re)) - ); + + if (isCollection(x)) { + return collection.map(x, sqrt); } - } - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.sqrt); - } + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return sqrt(x.valueOf()); + } - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.sqrt(x.valueOf()); - } - - throw newUnsupportedTypeError('sqrt', x); + throw new util.error.UnsupportedTypeError('sqrt', x); + }; }; diff --git a/src/function/arithmetic/square.js b/src/function/arithmetic/square.js index 316126cd0..7debfc6f4 100644 --- a/src/function/arithmetic/square.js +++ b/src/function/arithmetic/square.js @@ -1,35 +1,46 @@ -/** - * Compute the square of a value - * - * x .* x - * square(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ -math.square = function square(x) { - if (arguments.length != 1) { - throw newArgumentsError('square', arguments.length, 1); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (isNumber(x)) { - return x * x; - } + Complex = require('../../type/Complex.js'), + collection = require('../../type/collection.js'), - if (x instanceof Complex) { - return math.multiply(x, x); - } + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isCollection = collection.isCollection; - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.square); - } + /** + * Compute the square of a value + * + * x .* x + * square(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + */ + math.square = function square(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('square', arguments.length, 1); + } - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.square(x.valueOf()); - } + if (isNumber(x)) { + return x * x; + } - throw newUnsupportedTypeError('square', x); + if (isComplex(x)) { + return math.multiply(x, x); + } + + if (isCollection(x)) { + return collection.map(x, square); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return square(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('square', x); + }; }; diff --git a/src/function/arithmetic/subtract.js b/src/function/arithmetic/subtract.js index 8f36974eb..989e808b1 100644 --- a/src/function/arithmetic/subtract.js +++ b/src/function/arithmetic/subtract.js @@ -1,80 +1,94 @@ -/** - * Subtract two values - * - * x - y - * subtract(x, y) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Unit | Array | Matrix} x - * @param {Number | Complex | Unit | Array | Matrix} y - * @return {Number | Complex | Unit | Array | Matrix} res - */ -math.subtract = function subtract(x, y) { - if (arguments.length != 2) { - throw newArgumentsError('subtract', arguments.length, 2); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (isNumber(x)) { - if (isNumber(y)) { - // number - number - return x - y; + Complex = require('../../type/Complex.js'), + Matrix = require('../../type/Matrix.js'), + Unit = require('../../type/Unit.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isString = util.string.isString, + isComplex = Complex.isComplex, + isUnit = Unit.isUnit, + isCollection = collection.isCollection; + + /** + * Subtract two values + * + * x - y + * subtract(x, y) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Unit | Array | Matrix} x + * @param {Number | Complex | Unit | Array | Matrix} y + * @return {Number | Complex | Unit | Array | Matrix} res + */ + math.subtract = function subtract(x, y) { + if (arguments.length != 2) { + throw new util.error.ArgumentsError('subtract', arguments.length, 2); } - else if (y instanceof Complex) { - // number - complex - return Complex.create ( - x - y.re, - - y.im - ); - } - } - else if (x instanceof Complex) { - if (isNumber(y)) { - // complex - number - return Complex.create ( - x.re - y, - x.im - ) - } - else if (y instanceof Complex) { - // complex - complex - return Complex.create ( - x.re - y.re, - x.im - y.im - ) - } - } - else if (x instanceof Unit) { - if (y instanceof Unit) { - if (!x.equalBase(y)) { - throw new Error('Units do not match'); + + if (isNumber(x)) { + if (isNumber(y)) { + // number - number + return x - y; } - - if (x.value == null) { - throw new Error('Unit on left hand side of operator - has an undefined value'); + else if (isComplex(y)) { + // number - complex + return Complex.create ( + x - y.re, + - y.im + ); } - - if (y.value == null) { - throw new Error('Unit on right hand side of operator - has an undefined value'); - } - - var res = x.clone(); - res.value -= y.value; - res.fixPrefix = false; - - return res; } - } + else if (isComplex(x)) { + if (isNumber(y)) { + // complex - number + return Complex.create ( + x.re - y, + x.im + ) + } + else if (isComplex(y)) { + // complex - complex + return Complex.create ( + x.re - y.re, + x.im - y.im + ) + } + } + else if (isUnit(x)) { + if (isUnit(y)) { + if (!x.equalBase(y)) { + throw new Error('Units do not match'); + } - if (Array.isArray(x) || x instanceof Matrix || - Array.isArray(y) || y instanceof Matrix) { - return util.map2(x, y, math.subtract); - } + if (x.value == null) { + throw new Error('Unit on left hand side of operator - has an undefined value'); + } - if (x.valueOf() !== x || y.valueOf() !== y) { - // fallback on the objects primitive values - return math.subtract(x.valueOf(), y.valueOf()); - } + if (y.value == null) { + throw new Error('Unit on right hand side of operator - has an undefined value'); + } - throw newUnsupportedTypeError('subtract', x, y); + var res = x.clone(); + res.value -= y.value; + res.fixPrefix = false; + + return res; + } + } + + if (isCollection(x) || isCollection(y)) { + return collection.map2(x, y, subtract); + } + + if (x.valueOf() !== x || y.valueOf() !== y) { + // fallback on the objects primitive values + return subtract(x.valueOf(), y.valueOf()); + } + + throw new util.error.UnsupportedTypeError('subtract', x, y); + }; }; diff --git a/src/function/arithmetic/unary.js b/src/function/arithmetic/unary.js index 856e3b01e..0375aebab 100644 --- a/src/function/arithmetic/unary.js +++ b/src/function/arithmetic/unary.js @@ -1,47 +1,55 @@ -/** - * Inverse the sign of a value. - * - * -x - * unary(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Unit | Array | Matrix} x - * @return {Number | Complex | Unit | Array | Matrix} res - */ -math.unary = function unary(x) { - if (arguments.length != 1) { - throw newArgumentsError('unary', arguments.length, 1); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (isNumber(x)) { - return -x; - } - else if (x instanceof Complex) { - return Complex.create( - -x.re, - -x.im - ); - } - else if (x instanceof Unit) { - var res = x.clone(); - res.value = -x.value; - return res; - } + Complex = require('../../type/Complex.js'), + Unit = require('../../type/Unit.js'), + collection = require('../../type/collection.js'), - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.unary); - } + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isUnit = Unit.isUnit, + isCollection = collection.isCollection; - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.unary(x.valueOf()); - } + /** + * Inverse the sign of a value. + * + * -x + * unary(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Unit | Array | Matrix} x + * @return {Number | Complex | Unit | Array | Matrix} res + */ + math.unary = function unary(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('unary', arguments.length, 1); + } - throw newUnsupportedTypeError('unary', x); -}; - -// TODO: deprecated since version 0.10.0, cleanup some day -math.unaryminus = function unaryminus(x) { - throw new Error('Function unaryminus is deprecated, use unary instead'); + if (isNumber(x)) { + return -x; + } + else if (isComplex(x)) { + return Complex.create( + -x.re, + -x.im + ); + } + else if (isUnit(x)) { + var res = x.clone(); + res.value = -x.value; + return res; + } + + if (isCollection(x)) { + return collection.map(x, unary); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return unary(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('unary', x); + }; }; diff --git a/src/function/arithmetic/unequal.js b/src/function/arithmetic/unequal.js index f5fe92c7e..39b828b4f 100644 --- a/src/function/arithmetic/unequal.js +++ b/src/function/arithmetic/unequal.js @@ -1,53 +1,66 @@ -/** - * Check if value x unequals y, x != y - * In case of complex numbers, x.re must unequal y.re, or x.im must unequal y.im - * @param {Number | Complex | Unit | String | Array | Matrix | Range} x - * @param {Number | Complex | Unit | String | Array | Matrix | Range} y - * @return {Boolean | Array | Matrix} res - */ -math.unequal = function unequal(x, y) { - if (arguments.length != 2) { - throw newArgumentsError('unequal', arguments.length, 2); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (isNumber(x)) { - if (isNumber(y)) { + Complex = require('../../type/Complex.js'), + Unit = require('../../type/Unit.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isString = util.string.isString, + isComplex = Complex.isComplex, + isUnit = Unit.isUnit, + isCollection = collection.isCollection; + + /** + * Check if value x unequals y, x != y + * In case of complex numbers, x.re must unequal y.re, or x.im must unequal y.im + * @param {Number | Complex | Unit | String | Array | Matrix | Range} x + * @param {Number | Complex | Unit | String | Array | Matrix | Range} y + * @return {Boolean | Array | Matrix} res + */ + math.unequal = function unequal(x, y) { + if (arguments.length != 2) { + throw new util.error.ArgumentsError('unequal', arguments.length, 2); + } + + if (isNumber(x)) { + if (isNumber(y)) { + return x != y; + } + else if (isComplex(y)) { + return (x != y.re) || (y.im != 0); + } + } + + if (isComplex(x)) { + if (isNumber(y)) { + return (x.re != y) || (x.im != 0); + } + else if (isComplex(y)) { + return (x.re != y.re) || (x.im != y.im); + } + } + + if ((isUnit(x)) && (isUnit(y))) { + if (!x.equalBase(y)) { + throw new Error('Cannot compare units with different base'); + } + return x.value != y.value; + } + + if (isString(x) || isString(y)) { return x != y; } - else if (y instanceof Complex) { - return (x != y.re) || (y.im != 0); + + if (isCollection(x) || isCollection(y)) { + return collection.map2(x, y, unequal); } - } - if (x instanceof Complex) { - if (isNumber(y)) { - return (x.re != y) || (x.im != 0); + if (x.valueOf() !== x || y.valueOf() !== y) { + // fallback on the objects primitive values + return unequal(x.valueOf(), y.valueOf()); } - else if (y instanceof Complex) { - return (x.re != y.re) || (x.im != y.im); - } - } - if ((x instanceof Unit) && (y instanceof Unit)) { - if (!x.equalBase(y)) { - throw new Error('Cannot compare units with different base'); - } - return x.value != y.value; - } - - if (isString(x) || isString(y)) { - return x != y; - } - - if (Array.isArray(x) || x instanceof Matrix || - Array.isArray(y) || y instanceof Matrix) { - return util.map2(x, y, math.unequal); - } - - if (x.valueOf() !== x || y.valueOf() !== y) { - // fallback on the objects primitive values - return math.unequal(x.valueOf(), y.valueOf()); - } - - throw newUnsupportedTypeError('unequal', x, y); + throw new util.error.UnsupportedTypeError('unequal', x, y); + }; }; diff --git a/src/function/arithmetic/xgcd.js b/src/function/arithmetic/xgcd.js index e7f3dea0f..906b0b9a7 100644 --- a/src/function/arithmetic/xgcd.js +++ b/src/function/arithmetic/xgcd.js @@ -1,38 +1,45 @@ -/** - * Calculate the extended greatest common divisor for two values. - * - * xgcd(a, b) - * - * @param {Number} a An integer number - * @param {Number} b An integer number - * @return {Array} An array containing 3 integers [div, m, n] - * where div = gcd(a, b) and a*m + b*n = div - * - * @see http://en.wikipedia.org/wiki/Extended_Euclidean_algorithm - */ -math.xgcd = function xgcd(a, b) { - if (arguments.length == 2) { - // two arguments - if (isNumber(a) && isNumber(b)) { - if (!isInteger(a) || !isInteger(b)) { - throw new Error('Parameters in function xgcd must be integer numbers'); +module.exports = function (math) { + var util = require('../../util/index.js'), + + isNumber = util.number.isNumber, + isInteger = util.number.isInteger; + + /** + * Calculate the extended greatest common divisor for two values. + * + * xgcd(a, b) + * + * @param {Number} a An integer number + * @param {Number} b An integer number + * @return {Array} An array containing 3 integers [div, m, n] + * where div = gcd(a, b) and a*m + b*n = div + * + * @see http://en.wikipedia.org/wiki/Extended_Euclidean_algorithm + */ + math.xgcd = function xgcd(a, b) { + if (arguments.length == 2) { + // two arguments + if (isNumber(a) && isNumber(b)) { + if (!isInteger(a) || !isInteger(b)) { + throw new Error('Parameters in function xgcd must be integer numbers'); + } + + if(b == 0) { + return [a, 1, 0]; + } + + var tmp = xgcd(b, a % b), + div = tmp[0], + x = tmp[1], + y = tmp[2]; + + return [div, y, x - y * Math.floor(a / b)]; } - if(b == 0) { - return [a, 1, 0]; - } - - var tmp = xgcd(b, a % b), - div = tmp[0], - x = tmp[1], - y = tmp[2]; - - return [div, y, x - y * Math.floor(a / b)]; + throw new util.error.UnsupportedTypeError('xgcd', a, b); } - throw newUnsupportedTypeError('xgcd', a, b); - } - - // zero or one argument - throw new SyntaxError('Function xgcd expects two arguments'); + // zero or one argument + throw new SyntaxError('Function xgcd expects two arguments'); + }; }; diff --git a/src/function/complex/arg.js b/src/function/complex/arg.js index 11409dab1..a7bd691ff 100644 --- a/src/function/complex/arg.js +++ b/src/function/complex/arg.js @@ -1,36 +1,47 @@ -/** - * Compute the argument of a complex value. - * If x = a + bi, the argument is computed as atan2(b, a). - * - * arg(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Array | Matrix} res - */ -math.arg = function arg(x) { - if (arguments.length != 1) { - throw newArgumentsError('arg', arguments.length, 1); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (isNumber(x)) { - return Math.atan2(0, x); - } + Complex = require('../../type/Complex.js'), + collection = require('../../type/collection.js'), - if (x instanceof Complex) { - return Math.atan2(x.im, x.re); - } + isNumber = util.number.isNumber, + isCollection =collection.isCollection, + isComplex = Complex.isComplex; - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.arg); - } + /** + * Compute the argument of a complex value. + * If x = a + bi, the argument is computed as atan2(b, a). + * + * arg(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Array | Matrix} res + */ + math.arg = function arg(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('arg', arguments.length, 1); + } - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.arg(x.valueOf()); - } + if (isNumber(x)) { + return Math.atan2(0, x); + } - // handle other types just as non-complex values - return math.atan2(0, x); + if (isComplex(x)) { + return Math.atan2(x.im, x.re); + } + + if (isCollection(x)) { + return collection.map(x, arg); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return arg(x.valueOf()); + } + + // handle other types just as non-complex values + return math.atan2(0, x); + }; }; diff --git a/src/function/complex/conj.js b/src/function/complex/conj.js index 2e666f220..5790e1444 100644 --- a/src/function/complex/conj.js +++ b/src/function/complex/conj.js @@ -1,36 +1,48 @@ -/** - * Compute the complex conjugate of a complex value. - * If x = a+bi, the complex conjugate is a-bi. - * - * conj(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ -math.conj = function conj(x) { - if (arguments.length != 1) { - throw newArgumentsError('conj', arguments.length, 1); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (isNumber(x)) { - return x; - } + Complex = require('../../type/Complex.js'), + collection = require('../../type/collection.js'), - if (x instanceof Complex) { - return Complex.create(x.re, -x.im); - } + object = util.object, + isNumber = util.number.isNumber, + isCollection =collection.isCollection, + isComplex = Complex.isComplex; - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.conj); - } + /** + * Compute the complex conjugate of a complex value. + * If x = a+bi, the complex conjugate is a-bi. + * + * conj(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + */ + math.conj = function conj(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('conj', arguments.length, 1); + } - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.conj(x.valueOf()); - } + if (isNumber(x)) { + return x; + } - // return a clone of the value for non-complex values - return clone(x); + if (isComplex(x)) { + return Complex.create(x.re, -x.im); + } + + if (isCollection(x)) { + return collection.map(x, conj); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return conj(x.valueOf()); + } + + // return a clone of the value for non-complex values + return object.clone(x); + }; }; diff --git a/src/function/complex/im.js b/src/function/complex/im.js index af9351ec9..9ce9aa552 100644 --- a/src/function/complex/im.js +++ b/src/function/complex/im.js @@ -1,35 +1,46 @@ -/** - * Get the imaginary part of a complex number. - * - * im(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Array | Matrix} im - */ -math.im = function im(x) { - if (arguments.length != 1) { - throw newArgumentsError('im', arguments.length, 1); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (isNumber(x)) { + Complex = require('../../type/Complex.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isCollection =collection.isCollection, + isComplex = Complex.isComplex; + + /** + * Get the imaginary part of a complex number. + * + * im(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Array | Matrix} im + */ + math.im = function im(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('im', arguments.length, 1); + } + + if (isNumber(x)) { + return 0; + } + + if (isComplex(x)) { + return x.im; + } + + if (isCollection(x)) { + return collection.map(x, im); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return im(x.valueOf()); + } + + // return 0 for all non-complex values return 0; - } - - if (x instanceof Complex) { - return x.im; - } - - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.im); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.im(x.valueOf()); - } - - // return 0 for all non-complex values - return 0; + }; }; diff --git a/src/function/complex/re.js b/src/function/complex/re.js index 392437f9b..1b26b49d4 100644 --- a/src/function/complex/re.js +++ b/src/function/complex/re.js @@ -1,35 +1,47 @@ -/** - * Get the real part of a complex number. - * - * re(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Array | Matrix} re - */ -math.re = function re(x) { - if (arguments.length != 1) { - throw newArgumentsError('re', arguments.length, 1); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (isNumber(x)) { - return x; - } + Complex = require('../../type/Complex.js'), + collection = require('../../type/collection.js'), - if (x instanceof Complex) { - return x.re; - } + object = util.object, + isNumber = util.number.isNumber, + isCollection =collection.isCollection, + isComplex = Complex.isComplex; - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.re); - } + /** + * Get the real part of a complex number. + * + * re(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Array | Matrix} re + */ + math.re = function re(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('re', arguments.length, 1); + } - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.re(x.valueOf()); - } + if (isNumber(x)) { + return x; + } - // return a clone of the value itself for all non-complex values - return math.clone(x); + if (isComplex(x)) { + return x.re; + } + + if (isCollection(x)) { + return collection.map(x, re); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return re(x.valueOf()); + } + + // return a clone of the value itself for all non-complex values + return object.clone(x); + }; }; diff --git a/src/function/construction/boolean.js b/src/function/construction/boolean.js index 2fb5784be..0493cb55f 100644 --- a/src/function/construction/boolean.js +++ b/src/function/construction/boolean.js @@ -1,41 +1,48 @@ -/** - * Create a boolean or convert a string or number to a boolean. - * In case of a number, true is returned for non-zero numbers, and false in - * case of zero. - * Strings can be 'true' or 'false', or can contain a number. - * @param {String | Number | Boolean} value - * @return {Boolean} bool - */ -math['boolean'] = function (value) { - if (arguments.length != 1) { - throw newArgumentsError('boolean', arguments.length, 0, 1); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (value === 'true' || value === true) { - return true; - } - else if (value === 'false' || value === false) { - return false; - } - else if (isNumber(value)) { - return (value !== 0); - } - else if (isString(value)) { - // try case insensitive - var lcase = value.toLowerCase(); - if (lcase === 'true') { + isNumber = util.number.isNumber, + isString = util.string.isString; + + /** + * Create a boolean or convert a string or number to a boolean. + * In case of a number, true is returned for non-zero numbers, and false in + * case of zero. + * Strings can be 'true' or 'false', or can contain a number. + * @param {String | Number | Boolean} value + * @return {Boolean} bool + */ + math['boolean'] = function bool (value) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('boolean', arguments.length, 0, 1); + } + + if (value === 'true' || value === true) { return true; } - else if (lcase === 'false') { + else if (value === 'false' || value === false) { return false; } - - // try whether a number - var num = Number(value); - if (value != '' && !isNaN(num)) { - return (num !== 0); + else if (isNumber(value)) { + return (value !== 0); } - } + else if (isString(value)) { + // try case insensitive + var lcase = value.toLowerCase(); + if (lcase === 'true') { + return true; + } + else if (lcase === 'false') { + return false; + } - throw new SyntaxError(value.toString() + ' is no valid boolean'); + // try whether a number + var num = Number(value); + if (value != '' && !isNaN(num)) { + return (num !== 0); + } + } + + throw new SyntaxError(value.toString() + ' is no valid boolean'); + }; }; diff --git a/src/function/construction/complex.js b/src/function/construction/complex.js index 56470697f..fa8384411 100644 --- a/src/function/construction/complex.js +++ b/src/function/construction/complex.js @@ -1,60 +1,69 @@ -/** - * Create a complex value. Depending on the passed arguments, the function - * will create and return a new math.type.Complex object. - * - * The method accepts the following arguments: - * complex() creates a complex value with zero - * as real and imaginary part. - * complex(re : number, im : string) creates a complex value with provided - * values for real and imaginary part. - * complex(arg : string) parses a string into a complex value. - * - * Example usage: - * var a = math.complex(3, -4); // 3 - 4i - * a.re = 5; // a = 5 - 4i - * var i = a.im; // -4; - * var b = math.complex('2 + 6i'); // 2 + 6i - * var c = math.complex(); // 0 + 0i - * var d = math.add(a, b); // 5 + 2i - * - * @param {*} [args] - * @return {Complex} value - */ -math.complex = function complex(args) { - switch (arguments.length) { - case 0: - // no parameters. Set re and im zero - return new Complex(0, 0); - break; +module.exports = function (math) { + var util = require('../../util/index.js'), - case 1: - // parse string into a complex number - var arg = arguments[0]; - if (arg instanceof Complex) { - // create a clone - return arg.clone(); - } - else if (isString(arg)) { - var c = Complex.parse(arg); - if (c) { - return c; + Complex = require('../../type/Complex.js'), + + isString = util.string.isString, + isComplex = Complex.isComplex; + + /** + * Create a complex value. Depending on the passed arguments, the function + * will create and return a new math.type.Complex object. + * + * The method accepts the following arguments: + * complex() creates a complex value with zero + * as real and imaginary part. + * complex(re : number, im : string) creates a complex value with provided + * values for real and imaginary part. + * complex(arg : string) parses a string into a complex value. + * + * Example usage: + * var a = math.complex(3, -4); // 3 - 4i + * a.re = 5; // a = 5 - 4i + * var i = a.im; // -4; + * var b = math.complex('2 + 6i'); // 2 + 6i + * var c = math.complex(); // 0 + 0i + * var d = math.add(a, b); // 5 + 2i + * + * @param {*} [args] + * @return {Complex} value + */ + math.complex = function complex(args) { + switch (arguments.length) { + case 0: + // no parameters. Set re and im zero + return new Complex(0, 0); + break; + + case 1: + // parse string into a complex number + var arg = arguments[0]; + if (isComplex(arg)) { + // create a clone + return arg.clone(); + } + else if (isString(arg)) { + var c = Complex.parse(arg); + if (c) { + return c; + } + else { + throw new SyntaxError('String "' + arg + '" is no valid complex number'); + } } else { - throw new SyntaxError('String "' + arg + '" is no valid complex number'); + throw new TypeError( + 'Two numbers or a single string expected in function complex'); } - } - else { - throw new TypeError( - 'Two numbers or a single string expected in function complex'); - } - break; + break; - case 2: - // re and im provided - return new Complex(arguments[0], arguments[1]); - break; + case 2: + // re and im provided + return new Complex(arguments[0], arguments[1]); + break; - default: - throw newArgumentsError('complex', arguments.length, 0, 2); - } + default: + throw new util.error.ArgumentsError('complex', arguments.length, 0, 2); + } + }; }; diff --git a/src/function/construction/matrix.js b/src/function/construction/matrix.js index 8866f4a0e..5fd34b4ac 100644 --- a/src/function/construction/matrix.js +++ b/src/function/construction/matrix.js @@ -1,24 +1,30 @@ -/** - * Create a matrix. The function creates a new math.type.Matrix object. - * - * The method accepts the following arguments: - * matrix() creates an empty matrix - * matrix(data) creates a matrix with initial data. - * - * Example usage: - * var m = matrix([[1, 2], [3, 4]); - * m.size(); // [2, 2] - * m.resize([3, 2], 5); - * m.valueOf(); // [[1, 2], [3, 4], [5, 5]] - * m.get([1, 0]) // 3 - * - * @param {Array | Matrix} [data] A multi dimensional array - * @return {Matrix} matrix - */ -math.matrix = function matrix(data) { - if (arguments.length > 1) { - throw newArgumentsError('matrix', arguments.length, 0, 1); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - return new Matrix(data); + Matrix = require('../../type/Matrix.js'); + + /** + * Create a matrix. The function creates a new math.type.Matrix object. + * + * The method accepts the following arguments: + * matrix() creates an empty matrix + * matrix(data) creates a matrix with initial data. + * + * Example usage: + * var m = matrix([[1, 2], [3, 4]); + * m.size(); // [2, 2] + * m.resize([3, 2], 5); + * m.valueOf(); // [[1, 2], [3, 4], [5, 5]] + * m.get([1, 0]) // 3 + * + * @param {Array | Matrix} [data] A multi dimensional array + * @return {Matrix} matrix + */ + math.matrix = function matrix(data) { + if (arguments.length > 1) { + throw new util.error.ArgumentsError('matrix', arguments.length, 0, 1); + } + + return new Matrix(data); + }; }; diff --git a/src/function/construction/number.js b/src/function/construction/number.js index 773eb6b88..81a6a3d08 100644 --- a/src/function/construction/number.js +++ b/src/function/construction/number.js @@ -1,22 +1,26 @@ -/** - * Create a number or convert a string to a number - * @param {String | Number | Boolean} [value] - * @return {Number} num - */ -math.number = function (value) { - switch (arguments.length) { - case 0: - return 0; - case 1: - var num = Number(value); - if (isNaN(num)) { - num = Number(value.valueOf()); - } - if (isNaN(num)) { - throw new SyntaxError(value.toString() + ' is no valid number'); - } - return num; - default: - throw newArgumentsError('number', arguments.length, 0, 1); - } +module.exports = function (math) { + var util = require('../../util/index.js'); + + /** + * Create a number or convert a string to a number + * @param {String | Number | Boolean} [value] + * @return {Number} num + */ + math.number = function number (value) { + switch (arguments.length) { + case 0: + return 0; + case 1: + var num = Number(value); + if (isNaN(num)) { + num = Number(value.valueOf()); + } + if (isNaN(num)) { + throw new SyntaxError(value.toString() + ' is no valid number'); + } + return num; + default: + throw new util.error.ArgumentsError('number', arguments.length, 0, 1); + } + }; }; diff --git a/src/function/construction/parser.js b/src/function/construction/parser.js index 2b57887a6..80ad4eb7a 100644 --- a/src/function/construction/parser.js +++ b/src/function/construction/parser.js @@ -1,39 +1,45 @@ -/** - * Create a parser. The function creates a new math.expr.Parser object. - * - * parser() - * - * Example usage: - * var parser = new math.parser(); - * - * // evaluate expressions - * var a = parser.eval('sqrt(3^2 + 4^2)'); // 5 - * var b = parser.eval('sqrt(-4)'); // 2i - * var c = parser.eval('2 inch in cm'); // 5.08 cm - * var d = parser.eval('cos(45 deg)'); // 0.7071067811865476 - * - * // define variables and functions - * parser.eval('x = 7 / 2'); // 3.5 - * parser.eval('x + 3'); // 6.5 - * parser.eval('function f(x, y) = x^y'); // f(x, y) - * parser.eval('f(2, 3)'); // 8 - * - * // get and set variables and functions - * var x = parser.get('x'); // 7 - * var f = parser.get('f'); // function - * var g = f(3, 2); // 9 - * parser.set('h', 500); - * var i = parser.eval('h / 2'); // 250 - * parser.set('hello', function (name) { +module.exports = function (math) { + var util = require('../../util/index.js'), + + Parser = require('../../expr/Parser.js'); + + /** + * Create a parser. The function creates a new math.expr.Parser object. + * + * parser() + * + * Example usage: + * var parser = new math.parser(); + * + * // evaluate expressions + * var a = parser.eval('sqrt(3^2 + 4^2)'); // 5 + * var b = parser.eval('sqrt(-4)'); // 2i + * var c = parser.eval('2 inch in cm'); // 5.08 cm + * var d = parser.eval('cos(45 deg)'); // 0.7071067811865476 + * + * // define variables and functions + * parser.eval('x = 7 / 2'); // 3.5 + * parser.eval('x + 3'); // 6.5 + * parser.eval('function f(x, y) = x^y'); // f(x, y) + * parser.eval('f(2, 3)'); // 8 + * + * // get and set variables and functions + * var x = parser.get('x'); // 7 + * var f = parser.get('f'); // function + * var g = f(3, 2); // 9 + * parser.set('h', 500); + * var i = parser.eval('h / 2'); // 250 + * parser.set('hello', function (name) { * return 'hello, ' + name + '!'; * }); - * parser.eval('hello("user")'); // "hello, user!" - * - * // clear defined functions and variables - * parser.clear(); - * - * @return {math.expr.Parser} Parser - */ -math.parser = function parser() { - return new math.expr.Parser(); + * parser.eval('hello("user")'); // "hello, user!" + * + * // clear defined functions and variables + * parser.clear(); + * + * @return {Parser} Parser + */ + math.parser = function parser() { + return new Parser(); + }; }; diff --git a/src/function/construction/range.js b/src/function/construction/range.js index 0aa9e1c9b..3213ae12b 100644 --- a/src/function/construction/range.js +++ b/src/function/construction/range.js @@ -1,65 +1,73 @@ -/** - * Create a range. The function creates a new math.type.Range object. - * - * A range works similar to an Array, with functions like - * forEach and map. However, a Range object is very cheap to create compared to - * a large Array with indexes, as it stores only a start, step and end value of - * the range. - * - * The method accepts the following arguments - * range(str) Create a range from a string, where the - * string contains the start, optional step, - * and end, separated by a colon. - * range(start, end) Create a range with start and end and a - * default step size of 1 - * range(start, step, end) Create a range with start, step, and end. - * - * Example usage: - * var c = math.range(2, 1, 5); // 2:1:5 - * c.toArray(); // [2, 3, 4, 5] - * var d = math.range(2, -1, -2); // 2:-1:-2 - * d.forEach(function (value, index) { +module.exports = function (math) { + var util = require('../../util/index.js'), + + Range = require('../../type/Range.js'), + + isString = util.string.isString; + + /** + * Create a range. The function creates a new math.type.Range object. + * + * A range works similar to an Array, with functions like + * forEach and map. However, a Range object is very cheap to create compared to + * a large Array with indexes, as it stores only a start, step and end value of + * the range. + * + * The method accepts the following arguments + * range(str) Create a range from a string, where the + * string contains the start, optional step, + * and end, separated by a colon. + * range(start, end) Create a range with start and end and a + * default step size of 1 + * range(start, step, end) Create a range with start, step, and end. + * + * Example usage: + * var c = math.range(2, 1, 5); // 2:1:5 + * c.toArray(); // [2, 3, 4, 5] + * var d = math.range(2, -1, -2); // 2:-1:-2 + * d.forEach(function (value, index) { * console.log(index, value); * }); - * var e = math.range('2:1:5'); // 2:1:5 - * - * @param {...*} args - * @return {Range} range - */ -math.range = function range(args) { - switch (arguments.length) { - case 1: - // parse string into a range - if (args instanceof Range) { - // create a clone - return args.clone(); - } - else if (isString(args)) { - var r = Range.parse(args); - if (r) { - return r; + * var e = math.range('2:1:5'); // 2:1:5 + * + * @param {...*} args + * @return {Range} range + */ + math.range = function range(args) { + switch (arguments.length) { + case 1: + // parse string into a range + if (args instanceof Range) { + // create a clone + return args.clone(); + } + else if (isString(args)) { + var r = Range.parse(args); + if (r) { + return r; + } + else { + throw new SyntaxError('String "' + r + '" is no valid range'); + } } else { - throw new SyntaxError('String "' + r + '" is no valid range'); + throw new TypeError( + 'Two or three numbers or a single string expected in function range'); } - } - else { - throw new TypeError( - 'Two or three numbers or a single string expected in function range'); - } - break; + break; - case 2: - // range(start, end) - return new Range(arguments[0], null, arguments[1]); - break; + case 2: + // range(start, end) + return new Range(arguments[0], null, arguments[1]); + break; - case 3: - // range(start, step, end) - return new Range(arguments[0], arguments[1], arguments[2]); - break; + case 3: + // range(start, step, end) + return new Range(arguments[0], arguments[1], arguments[2]); + break; - default: - throw newArgumentsError('range', arguments.length, 2, 3); - } + default: + throw new util.error.ArgumentsError('range', arguments.length, 2, 3); + } + }; }; diff --git a/src/function/construction/string.js b/src/function/construction/string.js index a15819ed4..f27d37065 100644 --- a/src/function/construction/string.js +++ b/src/function/construction/string.js @@ -1,46 +1,56 @@ -/** - * Create a string or convert any object into a string - * @param {*} [value] - * @return {String} str - */ -math.string = function (value) { - switch (arguments.length) { - case 0: - return ''; +module.exports = function (math) { + var util = require('../../util/index.js'), - case 1: - return _toString(value); + collection = require('../../type/collection.js'), - default: - throw newArgumentsError('string', arguments.length, 0, 1); + number = util.number, + isNumber = util.number.isNumber, + isCollection = collection.isCollection; + + /** + * Create a string or convert any object into a string + * @param {*} [value] + * @return {String} str + */ + math.string = function string (value) { + switch (arguments.length) { + case 0: + return ''; + + case 1: + return _toString(value); + + default: + throw new util.error.ArgumentsError('string', arguments.length, 0, 1); + } + }; + + /** + * Recursive toString function + * @param {*} value Value can be anything: number, string, array, Matrix, ... + * @returns {String} str + * @private + */ + function _toString(value) { + if (isCollection(value)) { + var array = value.valueOf(); + + var str = '['; + var len = array.length; + for (var i = 0; i < len; i++) { + if (i != 0) { + str += ', '; + } + str += _toString(array[i]); + } + str += ']'; + return str; + } + else if (isNumber(value)) { + return number.format(value); + } + else { + return value.toString(); + } } }; - -/** - * Recursive toString function - * @param {*} value Value can be anything: number, string, array, Matrix, ... - * @returns {String} str - * @private - */ -function _toString(value) { - if (Array.isArray(value) || value instanceof Matrix || value instanceof Range) { - var array = value.valueOf(); - - var str = '['; - var len = array.length; - for (var i = 0; i < len; i++) { - if (i != 0) { - str += ', '; - } - str += _toString(array[i]); - } - str += ']'; - return str; - } - else if (isNumber(value)) { - return util.formatNumber(value); // no digits specified - } - else { - return value.toString(); - } -} \ No newline at end of file diff --git a/src/function/construction/unit.js b/src/function/construction/unit.js index 7e3784571..e5a311ba1 100644 --- a/src/function/construction/unit.js +++ b/src/function/construction/unit.js @@ -1,51 +1,59 @@ -/** - * Create a unit. Depending on the passed arguments, the function - * will create and return a new math.type.Unit object. - * - * The method accepts the following arguments: - * unit(unit : string) - * unit(value : number, unit : string - * - * Example usage: - * var a = math.unit(5, 'cm'); // 50 mm - * var b = math.unit('23 kg'); // 23 kg - * var c = math.in(a, math.unit('m'); // 0.05 m - * - * @param {*} args - * @return {Unit} value - */ -math.unit = function unit(args) { - switch(arguments.length) { - case 1: - // parse a string - var arg = arguments[0]; - if (arg instanceof Unit) { - // create a clone of the unit - return arg.clone(); - } - else if (isString(arg)) { - if (Unit.isPlainUnit(arg)) { - return new Unit(null, arg); // a pure unit +module.exports = function (math) { + var util = require('../../util/index.js'), + + Unit = require('../../type/Unit.js'), + + isString = util.string.isString; + + /** + * Create a unit. Depending on the passed arguments, the function + * will create and return a new math.type.Unit object. + * + * The method accepts the following arguments: + * unit(unit : string) + * unit(value : number, unit : string + * + * Example usage: + * var a = math.unit(5, 'cm'); // 50 mm + * var b = math.unit('23 kg'); // 23 kg + * var c = math.in(a, math.unit('m'); // 0.05 m + * + * @param {*} args + * @return {Unit} value + */ + math.unit = function unit(args) { + switch(arguments.length) { + case 1: + // parse a string + var arg = arguments[0]; + if (arg instanceof Unit) { + // create a clone of the unit + return arg.clone(); } + else if (isString(arg)) { + if (Unit.isPlainUnit(arg)) { + return new Unit(null, arg); // a pure unit + } - var u = Unit.parse(arg); // a unit with value, like '5cm' - if (u) { - return u; + var u = Unit.parse(arg); // a unit with value, like '5cm' + if (u) { + return u; + } + + throw new SyntaxError('String "' + arg + '" is no valid unit'); } + else { + throw new TypeError('A string or a number and string expected in function unit'); + } + break; - throw new SyntaxError('String "' + arg + '" is no valid unit'); - } - else { - throw new TypeError('A string or a number and string expected in function unit'); - } - break; + case 2: + // a number and a unit + return new Unit(arguments[0], arguments[1]); + break; - case 2: - // a number and a unit - return new Unit(arguments[0], arguments[1]); - break; - - default: - throw newArgumentsError('unit', arguments.length, 1, 2); - } + default: + throw new util.error.ArgumentsError('unit', arguments.length, 1, 2); + } + }; }; diff --git a/src/function/construction/workspace.js b/src/function/construction/workspace.js deleted file mode 100644 index f54273acd..000000000 --- a/src/function/construction/workspace.js +++ /dev/null @@ -1,3 +0,0 @@ -math.workspace = function () { - throw new Error('Workspace is no longer supported, sorry...'); -}; \ No newline at end of file diff --git a/src/function/matrix/concat.js b/src/function/matrix/concat.js index b0f1cadc6..69a7340b6 100644 --- a/src/function/matrix/concat.js +++ b/src/function/matrix/concat.js @@ -1,102 +1,115 @@ -/** - * Concatenate two or more matrices - * Usage: - * math.concat(A, B, C, ...) - * math.concat(A, B, C, ..., dim) - * - * Where the optional dim is the zero-based number of the dimension to be - * concatenated. - * - * @param {... Array | Matrix} args - * @return {Array | Matrix} res - */ -math.concat = function concat (args) { - var i, - len = arguments.length, - dim = -1, // zero-based dimension - prevDim, - asMatrix = false, - matrices = []; // contains multi dimensional arrays +module.exports = function (math) { + var util = require('../../util/index.js'), - for (i = 0; i < len; i++) { - var arg = arguments[i]; + Matrix = require('../../type/Matrix.js'), + collection = require('../../type/collection.js'), - // test whether we need to return a Matrix (if not we return an Array) - if (arg instanceof Matrix) { - asMatrix = true; - } + object = util.object, + array = util.array, + isNumber = util.number.isNumber, + isInteger = util.number.isInteger, + isCollection = collection.isCollection; - if ((i == len - 1) && isNumber(arg)) { - // last argument contains the dimension on which to concatenate - prevDim = dim; - dim = arg; + /** + * Concatenate two or more matrices + * Usage: + * math.concat(A, B, C, ...) + * math.concat(A, B, C, ..., dim) + * + * Where the optional dim is the zero-based number of the dimension to be + * concatenated. + * + * @param {... Array | Matrix} args + * @return {Array | Matrix} res + */ + math.concat = function concat (args) { + var i, + len = arguments.length, + dim = -1, // zero-based dimension + prevDim, + asMatrix = false, + matrices = []; // contains multi dimensional arrays - if (!isInteger(dim) || dim < 0) { - throw new TypeError('Dimension number must be a positive integer ' + - '(dim = ' + dim + ')'); + for (i = 0; i < len; i++) { + var arg = arguments[i]; + + // test whether we need to return a Matrix (if not we return an Array) + if (arg instanceof Matrix) { + asMatrix = true; } - if (i > 0 && dim > prevDim) { - throw new RangeError('Dimension out of range ' + - '(' + dim + ' > ' + prevDim + ')'); + if ((i == len - 1) && isNumber(arg)) { + // last argument contains the dimension on which to concatenate + prevDim = dim; + dim = arg; + + if (!isInteger(dim) || dim < 0) { + throw new TypeError('Dimension number must be a positive integer ' + + '(dim = ' + dim + ')'); + } + + if (i > 0 && dim > prevDim) { + throw new RangeError('Dimension out of range ' + + '(' + dim + ' > ' + prevDim + ')'); + } + } + else if (isCollection(arg)) { + // this is a matrix or array + var matrix = object.clone(arg).valueOf(); + var size = array.size(arg.valueOf()); + matrices[i] = matrix; + prevDim = dim; + dim = size.length - 1; + + // verify whether each of the matrices has the same number of dimensions + if (i > 0 && dim != prevDim) { + throw new RangeError('Dimension mismatch ' + + '(' + prevDim + ' != ' + dim + ')'); + } + } + else { + throw new util.error.UnsupportedTypeError('concat', arg); } } - else if (Array.isArray(arg) || arg instanceof Matrix) { - // this is a matrix or array - var matrix = math.clone(arg).valueOf(); - var size = math.size(arg).valueOf(); - matrices[i] = matrix; - prevDim = dim; - dim = size.length - 1; - // verify whether each of the matrices has the same number of dimensions - if (i > 0 && dim != prevDim) { - throw new RangeError('Dimension mismatch ' + - '(' + prevDim + ' != ' + dim + ')'); + if (matrices.length == 0) { + throw new SyntaxError('At least one matrix expected'); + } + + var res = matrices.shift(); + while (matrices.length) { + res = _concat(res, matrices.shift(), dim, 0); + } + + return asMatrix ? new Matrix(res) : res; + }; + + /** + * Recursively concatenate two matrices. + * The contents of the matrices is not cloned. + * @param {Array} a Multi dimensional array + * @param {Array} b Multi dimensional array + * @param {Number} concatDim The dimension on which to concatenate (zero-based) + * @param {Number} dim The current dim (zero-based) + * @return {Array} c The concatenated matrix + * @private + */ + function _concat(a, b, concatDim, dim) { + if (dim < concatDim) { + // recurse into next dimension + if (a.length != b.length) { + throw new Error('Dimensions mismatch (' + a.length + ' != ' + b.length + ')'); } + + var c = []; + for (var i = 0; i < a.length; i++) { + c[i] = _concat(a[i], b[i], concatDim, dim + 1); + } + return c; } else { - throw newUnsupportedTypeError('concat', arg); + // concatenate this dimension + return a.concat(b); } } - - if (matrices.length == 0) { - throw new SyntaxError('At least one matrix expected'); - } - - var res = matrices.shift(); - while (matrices.length) { - res = _concat(res, matrices.shift(), dim, 0); - } - - return asMatrix ? new Matrix(res) : res; }; - -/** - * Recursively concatenate two matrices. - * The contents of the matrices is not cloned. - * @param {Array} a Multi dimensional array - * @param {Array} b Multi dimensional array - * @param {Number} concatDim The dimension on which to concatenate (zero-based) - * @param {Number} dim The current dim (zero-based) - * @return {Array} c The concatenated matrix - * @private - */ -function _concat(a, b, concatDim, dim) { - if (dim < concatDim) { - // recurse into next dimension - if (a.length != b.length) { - throw new Error('Dimensions mismatch (' + a.length + ' != ' + b.length + ')'); - } - - var c = []; - for (var i = 0; i < a.length; i++) { - c[i] = _concat(a[i], b[i], concatDim, dim + 1); - } - return c; - } - else { - // concatenate this dimension - return a.concat(b); - } -} diff --git a/src/function/matrix/det.js b/src/function/matrix/det.js index 94fee3efd..32566a4bc 100644 --- a/src/function/matrix/det.js +++ b/src/function/matrix/det.js @@ -1,136 +1,143 @@ -/** - * @constructor det - * Calculate the determinant of a matrix - * - * det(x) - * - * @param {Array | Matrix} x - * @return {Number} determinant - */ -math.det = function det (x) { - if (arguments.length != 1) { - throw newArgumentsError('det', arguments.length, 1); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - var size = math.size(x).valueOf(); - switch (size.length) { - case 0: - // scalar - return math.clone(x); - break; + Matrix = require('../../type/Matrix.js'), - case 1: - // vector - if (size[0] == 1) { - return math.clone(x.valueOf()[0]); - } - else { - throw new RangeError('Matrix must be square ' + - '(size: ' + math.format(size) + ')'); - } - break; + object = util.object, + array = util.array, + string = util.string; - case 2: - // two dimensional array - var rows = size[0]; - var cols = size[1]; - if (rows == cols) { - return _det(x.valueOf(), rows, cols); - } - else { - throw new RangeError('Matrix must be square ' + - '(size: ' + math.format(size) + ')'); - } - break; + /** + * @constructor det + * Calculate the determinant of a matrix + * + * det(x) + * + * @param {Array | Matrix} x + * @return {Number} determinant + */ + math.det = function det (x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('det', arguments.length, 1); + } - default: - // multi dimensional array - throw new RangeError('Matrix must be two dimensional ' + - '(size: ' + math.format(size) + ')'); - } -}; - -/** - * Calculate the determinant of a matrix - * @param {Array[]} matrix A square, two dimensional matrix - * @param {Number} rows Number of rows of the matrix (zero-based) - * @param {Number} cols Number of columns of the matrix (zero-based) - * @returns {Number} det - * @private - */ -function _det (matrix, rows, cols) { - var multiply = math.multiply, - subtract = math.subtract; - - if (rows == 1) { - // this is a 1 x 1 matrix - return matrix[0][0]; - } - else if (rows == 2) { - // this is a 2 x 2 matrix - // the determinant of [a11,a12;a21,a22] is det = a11*a22-a21*a12 - return subtract( - multiply(matrix[0][0], matrix[1][1]), - multiply(matrix[1][0], matrix[0][1]) - ); - } - else { - // this is an n x n matrix - var det = 1; - var lead = 0; - for (var r = 0; r < rows; r++) { - if (lead >= cols) { + var size = array.size(x.valueOf()); + switch (size.length) { + case 0: + // scalar + return object.clone(x); break; - } - var i = r; - // Find the pivot element. - while (matrix[i][lead] == 0) { - i++; - if (i == rows) { - i = r; - lead++; - if (lead == cols) { - // We found the last pivot. - if (util.deepEqual(matrix, math.eye(rows).valueOf())) { - return math.round(det, 6); - } else { - return 0; + + case 1: + // vector + if (size[0] == 1) { + return object.clone(x.valueOf()[0]); + } + else { + throw new RangeError('Matrix must be square ' + + '(size: ' + string.format(size) + ')'); + } + break; + + case 2: + // two dimensional array + var rows = size[0]; + var cols = size[1]; + if (rows == cols) { + return _det(x.valueOf(), rows, cols); + } + else { + throw new RangeError('Matrix must be square ' + + '(size: ' + string.format(size) + ')'); + } + break; + + default: + // multi dimensional array + throw new RangeError('Matrix must be two dimensional ' + + '(size: ' + string.format(size) + ')'); + } + }; + + /** + * Calculate the determinant of a matrix + * @param {Array[]} matrix A square, two dimensional matrix + * @param {Number} rows Number of rows of the matrix (zero-based) + * @param {Number} cols Number of columns of the matrix (zero-based) + * @returns {Number} det + * @private + */ + function _det (matrix, rows, cols) { + if (rows == 1) { + // this is a 1 x 1 matrix + return matrix[0][0]; + } + else if (rows == 2) { + // this is a 2 x 2 matrix + // the determinant of [a11,a12;a21,a22] is det = a11*a22-a21*a12 + return math.subtract( + math.multiply(matrix[0][0], matrix[1][1]), + math.multiply(matrix[1][0], matrix[0][1]) + ); + } + else { + // this is an n x n matrix + var d = 1; + var lead = 0; + for (var r = 0; r < rows; r++) { + if (lead >= cols) { + break; + } + var i = r; + // Find the pivot element. + while (matrix[i][lead] == 0) { + i++; + if (i == rows) { + i = r; + lead++; + if (lead == cols) { + // We found the last pivot. + if (object.deepEqual(matrix, eye(rows).valueOf())) { + return math.round(d, 6); + } else { + return 0; + } } } } - } - if (i != r) { - // Swap rows i and r, which negates the determinant. - for (var a = 0; a < cols; a++) { - var temp = matrix[i][a]; - matrix[i][a] = matrix[r][a]; - matrix[r][a] = temp; - } - det *= -1; - } - // Scale row r and the determinant simultaneously. - var div = matrix[r][lead]; - for (var a = 0; a < cols; a++) { - matrix[r][a] = matrix[r][a] / div; - } - det *= div; - // Back-substitute upwards. - for (var j = 0; j < rows; j++) { - if (j != r) { - // Taking linear combinations does not change the det. - var c = matrix[j][lead]; + if (i != r) { + // Swap rows i and r, which negates the determinant. for (var a = 0; a < cols; a++) { - matrix[j][a] = matrix[j][a] - matrix[r][a] * c; + var temp = matrix[i][a]; + matrix[i][a] = matrix[r][a]; + matrix[r][a] = temp; + } + d *= -1; + } + // Scale row r and the determinant simultaneously. + var div = matrix[r][lead]; + for (var a = 0; a < cols; a++) { + matrix[r][a] = matrix[r][a] / div; + } + d *= div; + // Back-substitute upwards. + for (var j = 0; j < rows; j++) { + if (j != r) { + // Taking linear combinations does not change the det. + var c = matrix[j][lead]; + for (var a = 0; a < cols; a++) { + matrix[j][a] = matrix[j][a] - matrix[r][a] * c; + } } } + lead++; // Now looking for a pivot further right. + } + // If reduction did not result in the identity, the matrix is singular. + if (object.deepEqual(matrix, math.eye(rows).valueOf())) { + return math.round(d, 6); + } else { + return 0; } - lead++; // Now looking for a pivot further right. - } - // If reduction did not result in the identity, the matrix is singular. - if (util.deepEqual(matrix, math.eye(rows).valueOf())) { - return math.round(det, 6); - } else { - return 0; } } -} +}; diff --git a/src/function/matrix/diag.js b/src/function/matrix/diag.js index bf1d2f97f..867dd8104 100644 --- a/src/function/matrix/diag.js +++ b/src/function/matrix/diag.js @@ -1,76 +1,87 @@ -/** - * Create a diagonal matrix or retrieve the diagonal of a matrix - * - * diag(v) - * diag(v, k) - * diag(X) - * diag(X, k) - * - * TODO: more documentation on diag - * - * @param {Number | Matrix | Array} x - * @param {Number} [k] - * @return {Matrix} matrix - */ -math.diag = function diag (x, k) { - var data, vector, i, iMax; +module.exports = function (math) { + var util = require('../../util/index.js'), - if (arguments.length != 1 && arguments.length != 2) { - throw newArgumentsError('diag', arguments.length, 1, 2); - } + Range = require('../../type/Range.js'), + Matrix = require('../../type/Matrix.js'), - if (k) { - if (!isNumber(k) || !isInteger(k)) { - throw new TypeError ('Second parameter in function diag must be an integer'); + object = util.object, + isNumber = util.number.isNumber, + isInteger = util.number.isInteger; + + /** + * Create a diagonal matrix or retrieve the diagonal of a matrix + * + * diag(v) + * diag(v, k) + * diag(X) + * diag(X, k) + * + * TODO: more documentation on diag + * + * @param {Number | Matrix | Array} x + * @param {Number} [k] + * @return {Matrix} matrix + */ + math.diag = function diag (x, k) { + var data, vector, i, iMax; + + if (arguments.length != 1 && arguments.length != 2) { + throw new util.error.ArgumentsError('diag', arguments.length, 1, 2); } - } - else { - k = 0; - } - var kSuper = k > 0 ? k : 0; - var kSub = k < 0 ? -k : 0; - // convert to matrix - if (!(x instanceof Matrix) && !(x instanceof Range)) { - x = new Matrix(x); - } - - // get as array when the matrix is a vector - var s; - if (x.isVector()) { - x = x.toVector(); - s = [x.length]; - } - else { - s = x.size(); - } - - switch (s.length) { - case 1: - // x is a vector. create diagonal matrix - vector = x.valueOf(); - var matrix = new Matrix(); - matrix.resize([vector.length + kSub, vector.length + kSuper]); - data = matrix.valueOf(); - iMax = vector.length; - for (i = 0; i < iMax; i++) { - data[i + kSub][i + kSuper] = math.clone(vector[i]); + if (k) { + if (!isNumber(k) || !isInteger(k)) { + throw new TypeError ('Second parameter in function diag must be an integer'); } - return matrix; - break; + } + else { + k = 0; + } + var kSuper = k > 0 ? k : 0; + var kSub = k < 0 ? -k : 0; - case 2: - // x is a matrix get diagonal from matrix - vector = []; - data = x.valueOf(); - iMax = Math.min(s[0] - kSub, s[1] - kSuper); - for (i = 0; i < iMax; i++) { - vector[i] = math.clone(data[i + kSub][i + kSuper]); - } - return new Matrix(vector); - break; + // convert to matrix + if (!(x instanceof Matrix) && !(x instanceof Range)) { + x = new Matrix(x); + } - default: - throw new RangeError('Matrix for function diag must be 2 dimensional'); - } + // get as array when the matrix is a vector + var s; + if (x.isVector()) { + x = x.toVector(); + s = [x.length]; + } + else { + s = x.size(); + } + + switch (s.length) { + case 1: + // x is a vector. create diagonal matrix + vector = x.valueOf(); + var matrix = new Matrix(); + matrix.resize([vector.length + kSub, vector.length + kSuper]); + data = matrix.valueOf(); + iMax = vector.length; + for (i = 0; i < iMax; i++) { + data[i + kSub][i + kSuper] = object.clone(vector[i]); + } + return matrix; + break; + + case 2: + // x is a matrix get diagonal from matrix + vector = []; + data = x.valueOf(); + iMax = Math.min(s[0] - kSub, s[1] - kSuper); + for (i = 0; i < iMax; i++) { + vector[i] = object.clone(data[i + kSub][i + kSuper]); + } + return new Matrix(vector); + break; + + default: + throw new RangeError('Matrix for function diag must be 2 dimensional'); + } + }; }; diff --git a/src/function/matrix/eye.js b/src/function/matrix/eye.js index e50e9e29c..d19367165 100644 --- a/src/function/matrix/eye.js +++ b/src/function/matrix/eye.js @@ -1,48 +1,58 @@ -/** - * Create an identity matrix with size m x n - * - * eye(m) - * eye(m, n) - * - * TODO: more documentation on eye - * - * @param {...Number | Matrix | Array} size - * @return {Matrix} matrix - */ -math.eye = function eye (size) { - var args = util.argsToArray(arguments); - if (args.length == 0) { - args = [1, 1]; - } - else if (args.length == 1) { - args[1] = args[0]; - } - else if (args.length > 2) { - throw newArgumentsError('eye', args.length, 0, 2); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - var rows = args[0], - cols = args[1]; + Matrix = require('../../type/Matrix.js'), + collection = require('../../type/collection.js'), - if (!isNumber(rows) || !isInteger(rows) || rows < 1) { - throw new Error('Parameters in function eye must be positive integers'); - } - if (cols) { - if (!isNumber(cols) || !isInteger(cols) || cols < 1) { + isNumber = util.number.isNumber, + isInteger = util.number.isInteger; + + /** + * Create an identity matrix with size m x n + * + * eye(m) + * eye(m, n) + * + * TODO: more documentation on eye + * + * @param {...Number | Matrix | Array} size + * @return {Matrix} matrix + */ + math.eye = function eye (size) { + var args = collection.argsToArray(arguments); + if (args.length == 0) { + args = [1, 1]; + } + else if (args.length == 1) { + args[1] = args[0]; + } + else if (args.length > 2) { + throw new util.error.ArgumentsError('eye', args.length, 0, 2); + } + + var rows = args[0], + cols = args[1]; + + if (!isNumber(rows) || !isInteger(rows) || rows < 1) { throw new Error('Parameters in function eye must be positive integers'); } - } + if (cols) { + if (!isNumber(cols) || !isInteger(cols) || cols < 1) { + throw new Error('Parameters in function eye must be positive integers'); + } + } - // create and args the matrix - var matrix = new Matrix(); - matrix.resize(args); + // create and args the matrix + var matrix = new Matrix(); + matrix.resize(args); - // fill in ones on the diagonal - var min = math.min(args); - var data = matrix.valueOf(); - for (var d = 0; d < min; d++) { - data[d][d] = 1; - } + // fill in ones on the diagonal + var minimum = math.min(args); + var data = matrix.valueOf(); + for (var d = 0; d < minimum; d++) { + data[d][d] = 1; + } - return matrix; + return matrix; + }; }; diff --git a/src/function/matrix/inv.js b/src/function/matrix/inv.js index 21476c3f7..6aa7fd286 100644 --- a/src/function/matrix/inv.js +++ b/src/function/matrix/inv.js @@ -1,182 +1,185 @@ -/** - * Calculate the inverse of a matrix - * - * inv(x) - * - * TODO: more documentation on inv - * - * @param {Array | Matrix} x - * @return {Array | Matrix} inv - */ -math.inv = function inv (x) { - if (arguments.length != 1) { - throw newArgumentsError('inv', arguments.length, 1); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - var size = math.size(x).valueOf(); - switch (size.length) { - case 0: - // scalar - return math.divide(1, x); - break; + Matrix = require('../../type/Matrix.js'), - case 1: - // vector - if (size[0] == 1) { - if (x instanceof Matrix) { - return new Matrix([ - math.divide(1, x.valueOf()[0]) - ]); + string = util.string; + + /** + * Calculate the inverse of a matrix + * + * inv(x) + * + * TODO: more documentation on inv + * + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} inv + */ + math.inv = function inv (x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('inv', arguments.length, 1); + } + var size = math.size(x).valueOf(); + switch (size.length) { + case 0: + // scalar + return math.divide(1, x); + break; + + case 1: + // vector + if (size[0] == 1) { + if (x instanceof Matrix) { + return new Matrix([ + math.divide(1, x.valueOf()[0]) + ]); + } + else { + return [ + math.divide(1, x[0]) + ]; + } } else { - return [ - math.divide(1, x[0]) - ]; + throw new RangeError('Matrix must be square ' + + '(size: ' + string.format(size) + ')'); } - } - else { - throw new RangeError('Matrix must be square ' + - '(size: ' + math.format(size) + ')'); - } - break; + break; - case 2: - // two dimensional array - var rows = size[0]; - var cols = size[1]; - if (rows == cols) { - if (x instanceof Matrix) { - return new Matrix( - _inv(x.valueOf(), rows, cols) - ); + case 2: + // two dimensional array + var rows = size[0]; + var cols = size[1]; + if (rows == cols) { + if (x instanceof Matrix) { + return new Matrix( + _inv(x.valueOf(), rows, cols) + ); + } + else { + // return an Array + return _inv(x, rows, cols); + } } else { - // return an Array - return _inv(x, rows, cols); + throw new RangeError('Matrix must be square ' + + '(size: ' + string.format(size) + ')'); } - } - else { - throw new RangeError('Matrix must be square ' + - '(size: ' + math.format(size) + ')'); - } - break; + break; - default: - // multi dimensional array - throw new RangeError('Matrix must be two dimensional ' + - '(size: ' + math.format(size) + ')'); - } -}; - -/** - * Calculate the inverse of a square matrix - * @param {Array[]} matrix A square matrix - * @param {Number} rows Number of rows - * @param {Number} cols Number of columns, must equal rows - * @return {Array[]} inv Inverse matrix - * @private - */ -function _inv (matrix, rows, cols){ - var r, s, f, value, temp, - add = math.add, - unary = math.unary, - multiply = math.multiply, - divide = math.divide; - - if (rows == 1) { - // this is a 1 x 1 matrix - value = matrix[0][0]; - if (value == 0) { - throw Error('Cannot calculate inverse, determinant is zero'); + default: + // multi dimensional array + throw new RangeError('Matrix must be two dimensional ' + + '(size: ' + string.format(size) + ')'); } - return [[ - divide(1, value) - ]]; - } - else if (rows == 2) { - // this is a 2 x 2 matrix - var det = math.det(matrix); - if (det == 0) { - throw Error('Cannot calculate inverse, determinant is zero'); - } - return [ - [ - divide(matrix[1][1], det), - divide(unary(matrix[0][1]), det) - ], - [ - divide(unary(matrix[1][0]), det), - divide(matrix[0][0], det) - ] - ]; - } - else { - // this is a matrix of 3 x 3 or larger - // calculate inverse using gauss-jordan elimination - // http://en.wikipedia.org/wiki/Gaussian_elimination - // http://mathworld.wolfram.com/MatrixInverse.html - // http://math.uww.edu/~mcfarlat/inverse.htm + }; - // make a copy of the matrix (only the arrays, not of the elements) - var A = matrix.concat(); - for (r = 0; r < rows; r++) { - A[r] = A[r].concat(); - } + /** + * Calculate the inverse of a square matrix + * @param {Array[]} matrix A square matrix + * @param {Number} rows Number of rows + * @param {Number} cols Number of columns, must equal rows + * @return {Array[]} inv Inverse matrix + * @private + */ + function _inv (matrix, rows, cols){ + var r, s, f, value, temp; - // create an identity matrix which in the end will contain the - // matrix inverse - var B = math.eye(rows).valueOf(); - - // loop over all columns, and perform row reductions - for (var c = 0; c < cols; c++) { - // element Acc should be non zero. if not, swap content - // with one of the lower rows - r = c; - while (r < rows && A[r][c] == 0) { - r++; - } - if (r == rows || A[r][c] == 0) { + if (rows == 1) { + // this is a 1 x 1 matrix + value = matrix[0][0]; + if (value == 0) { throw Error('Cannot calculate inverse, determinant is zero'); } - if (r != c) { - temp = A[c]; A[c] = A[r]; A[r] = temp; - temp = B[c]; B[c] = B[r]; B[r] = temp; + return [[ + math.divide(1, value) + ]]; + } + else if (rows == 2) { + // this is a 2 x 2 matrix + var d = math.det(matrix); + if (d == 0) { + throw Error('Cannot calculate inverse, determinant is zero'); + } + return [ + [ + math.divide(matrix[1][1], d), + math.divide(math.unary(matrix[0][1]), d) + ], + [ + math.divide(math.unary(matrix[1][0]), d), + math.divide(matrix[0][0], d) + ] + ]; + } + else { + // this is a matrix of 3 x 3 or larger + // calculate inverse using gauss-jordan elimination + // http://en.wikipedia.org/wiki/Gaussian_elimination + // http://mathworld.wolfram.com/MatrixInverse.html + // http://math.uww.edu/~mcfarlat/inverse.htm + + // make a copy of the matrix (only the arrays, not of the elements) + var A = matrix.concat(); + for (r = 0; r < rows; r++) { + A[r] = A[r].concat(); } - // eliminate non-zero values on the other rows at column c - var Ac = A[c], - Bc = B[c]; - for (r = 0; r < rows; r++) { - var Ar = A[r], - Br = B[r]; - if(r != c) { - // eliminate value at column c and row r - if (Ar[c] != 0) { - f = divide(unary(Ar[c]), Ac[c]); + // create an identity matrix which in the end will contain the + // matrix inverse + var B = math.eye(rows).valueOf(); - // add (f * row c) to row r to eliminate the value - // at column c + // loop over all columns, and perform row reductions + for (var c = 0; c < cols; c++) { + // element Acc should be non zero. if not, swap content + // with one of the lower rows + r = c; + while (r < rows && A[r][c] == 0) { + r++; + } + if (r == rows || A[r][c] == 0) { + throw Error('Cannot calculate inverse, determinant is zero'); + } + if (r != c) { + temp = A[c]; A[c] = A[r]; A[r] = temp; + temp = B[c]; B[c] = B[r]; B[r] = temp; + } + + // eliminate non-zero values on the other rows at column c + var Ac = A[c], + Bc = B[c]; + for (r = 0; r < rows; r++) { + var Ar = A[r], + Br = B[r]; + if(r != c) { + // eliminate value at column c and row r + if (Ar[c] != 0) { + f = math.divide(math.unary(Ar[c]), Ac[c]); + + // add (f * row c) to row r to eliminate the value + // at column c + for (s = c; s < cols; s++) { + Ar[s] = math.add(Ar[s], math.multiply(f, Ac[s])); + } + for (s = 0; s < cols; s++) { + Br[s] = math.add(Br[s], math.multiply(f, Bc[s])); + } + } + } + else { + // normalize value at Acc to 1, + // divide each value on row r with the value at Acc + f = Ac[c]; for (s = c; s < cols; s++) { - Ar[s] = add(Ar[s], multiply(f, Ac[s])); + Ar[s] = math.divide(Ar[s], f); } for (s = 0; s < cols; s++) { - Br[s] = add(Br[s], multiply(f, Bc[s])); + Br[s] = math.divide(Br[s], f); } } } - else { - // normalize value at Acc to 1, - // divide each value on row r with the value at Acc - f = Ac[c]; - for (s = c; s < cols; s++) { - Ar[s] = divide(Ar[s], f); - } - for (s = 0; s < cols; s++) { - Br[s] = divide(Br[s], f); - } - } } + return B; } - return B; } -} +}; diff --git a/src/function/matrix/ones.js b/src/function/matrix/ones.js index fe8aefe4f..64395ada1 100644 --- a/src/function/matrix/ones.js +++ b/src/function/matrix/ones.js @@ -1,27 +1,34 @@ -/** - * Create a matrix filled with ones - * - * ones(n) - * ones(m, n) - * ones([m, n]) - * ones([m, n, p, ...]) - * - * @param {...Number | Array} size - * @return {Matrix} matrix - */ -math.ones = function ones (size) { - var args = util.argsToArray(arguments); +module.exports = function (math) { + var util = require('../../util/index.js'), - if (args.length == 0) { - args = [1, 1]; - } - else if (args.length == 1) { - args[1] = args[0]; - } + Matrix = require('../../type/Matrix.js'), + collection = require('../../type/collection.js'); - // create and size the matrix - var matrix = new Matrix(); - var defaultValue = 1; - matrix.resize(args, defaultValue); - return matrix; + /** + * Create a matrix filled with ones + * + * ones(n) + * ones(m, n) + * ones([m, n]) + * ones([m, n, p, ...]) + * + * @param {...Number | Array} size + * @return {Matrix} matrix + */ + math.ones = function ones (size) { + var args = collection.argsToArray(arguments); + + if (args.length == 0) { + args = [1, 1]; + } + else if (args.length == 1) { + args[1] = args[0]; + } + + // create and size the matrix + var matrix = new Matrix(); + var defaultValue = 1; + matrix.resize(args, defaultValue); + return matrix; + }; }; diff --git a/src/function/matrix/size.js b/src/function/matrix/size.js index aff30fbe8..317407f2a 100644 --- a/src/function/matrix/size.js +++ b/src/function/matrix/size.js @@ -1,36 +1,50 @@ -/** - * Calculate the size of a matrix or scalar - * - * size(x) - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ -math.size = function size (x) { - if (arguments.length != 1) { - throw newArgumentsError('size', arguments.length, 1); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (isNumber(x) || x instanceof Complex || x instanceof Unit || x == null) { - return []; - } + Complex = require('../../type/Complex.js'), + Unit = require('../../type/Unit.js'), + Matrix = require('../../type/Matrix.js'), - if (isString(x)) { - return [x.length]; - } + array = util.array, + isNumber = util.number.isNumber, + isString = util.string.isString, + isComplex = Complex.isComplex, + isUnit = Unit.isUnit; - if (Array.isArray(x)) { - return util.size(x); - } + /** + * Calculate the size of a matrix or scalar + * + * size(x) + * + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + */ + math.size = function size (x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('size', arguments.length, 1); + } - if (x instanceof Matrix) { - return new Matrix(x.size()); - } + if (isNumber(x) || isComplex(x) || isUnit(x) || x == null) { + return []; + } - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.size(x.valueOf()); - } + if (isString(x)) { + return [x.length]; + } - throw newUnsupportedTypeError('size', x); + if (Array.isArray(x)) { + return array.size(x); + } + + if (x instanceof Matrix) { + return new Matrix(x.size()); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return size(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('size', x); + }; }; diff --git a/src/function/matrix/squeeze.js b/src/function/matrix/squeeze.js index 79b1ff39e..a42c25cfe 100644 --- a/src/function/matrix/squeeze.js +++ b/src/function/matrix/squeeze.js @@ -1,50 +1,59 @@ -/** - * Remove singleton dimensions from a matrix - * - * squeeze(x) - * - * @param {Matrix | Array} x - * @return {Matrix | Array} res - */ -math.squeeze = function squeeze (x) { - if (arguments.length != 1) { - throw newArgumentsError('squeeze', arguments.length, 1); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (Array.isArray(x)) { - return _squeezeArray(math.clone(x)); - } - else if (x instanceof Matrix) { - return math.matrix(_squeezeArray(x.toArray())); - } - else if (Array.isArray(x.valueOf())) { - return _squeezeArray(math.clone(x.valueOf())); - } - else { - // scalar - return math.clone(x); + Matrix = require('../../type/Matrix.js'), + + object = util.object, + isArray = Array.isArray; + + /** + * Remove singleton dimensions from a matrix + * + * squeeze(x) + * + * @param {Matrix | Array} x + * @return {Matrix | Array} res + */ + math.squeeze = function squeeze (x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('squeeze', arguments.length, 1); + } + + if (isArray(x)) { + return _squeezeArray(object.clone(x)); + } + else if (x instanceof Matrix) { + return new Matrix(_squeezeArray(x.toArray())); + } + else if (isArray(x.valueOf())) { + return _squeezeArray(object.clone(x.valueOf())); + } + else { + // scalar + return object.clone(x); + } + }; + + /** + * Recursively squeeze a multi dimensional array + * @param {Array} array + * @return {Array} array + * @private + */ + function _squeezeArray(array) { + if (array.length == 1) { + // squeeze this array + return _squeezeArray(array[0]); + } + else { + // process all childs + for (var i = 0, len = array.length; i < len; i++) { + var child = array[i]; + if (isArray(child)) { + array[i] = _squeezeArray(child); + } + } + return array; + } } }; - -/** - * Recursively squeeze a multi dimensional array - * @param {Array} array - * @return {Array} array - * @private - */ -function _squeezeArray(array) { - if (array.length == 1) { - // squeeze this array - return _squeezeArray(array[0]); - } - else { - // process all childs - for (var i = 0, len = array.length; i < len; i++) { - var child = array[i]; - if (Array.isArray(child)) { - array[i] = _squeezeArray(child); - } - } - return array; - } -} diff --git a/src/function/matrix/subset.js b/src/function/matrix/subset.js index 94b184fb1..059390570 100644 --- a/src/function/matrix/subset.js +++ b/src/function/matrix/subset.js @@ -1,194 +1,205 @@ -/** - * Get or set a subset of a matrix or string - * - * Usage: - * var subset = math.subset(value, index) // retrieve subset - * var value = math.subset(value, index, replacement) // replace subset - * - * Where: - * {*} value An array, matrix, or scalar value - * {Array} index An array containing index values - * {*} replacement An array, matrix, or scalar - * - * @param args - * @return res - */ -math.subset = function subset (args) { - switch (arguments.length) { - case 2: // get subset - return _getSubset(arguments[0], arguments[1]); +module.exports = function (math) { + var util = require('../../util/index.js'), - case 3: // set subset - return _setSubset(arguments[0], arguments[1], arguments[2]); + Matrix = require('../../type/Matrix.js'), + Range = require('../../type/Range.js'), - default: // wrong number of arguments - throw newArgumentsError('subset', arguments.length, 2, 3); - } -}; + array = util.array, + isString = util.string.isString, + isArray = Array.isArray; -/** - * Retrieve a subset of an value such as an Array, Matrix, or String - * @param {*} value Object from which to get a subset - * @param {Array[] | Range[] | Number[] | Matrix} index - * Two dimensional array (size 1 x n) containing - * the indexes to be retrieved. Can also be a two - * dimensional Matrix (size 1 x n), or an Array - * (size 1) containing a Range or a Number. - * @returns {*} subset - * @private - */ -function _getSubset(value, index) { - var matrix, subset; + /** + * Get or set a subset of a matrix or string + * + * Usage: + * var subset = math.subset(value, index) // retrieve subset + * var value = math.subset(value, index, replacement) // replace subset + * + * Where: + * {*} value An array, matrix, or scalar value + * {Array} index An array containing index values + * {*} replacement An array, matrix, or scalar + * + * @param args + * @return res + */ + math.subset = function subset (args) { + switch (arguments.length) { + case 2: // get subset + return _getSubset(arguments[0], arguments[1]); - if (Array.isArray(value) || value instanceof Range) { - matrix = math.matrix(value); - subset = matrix.get(index); - return subset.valueOf(); - } - else if (value instanceof Matrix) { - return value.get(index); - } - else if (isString(value)) { - return _getSubstring(value, index); - } - else { - // scalar - matrix = math.matrix([value]); - subset = matrix.get(index); - return subset.valueOf(); - } -} + case 3: // set subset + return _setSubset(arguments[0], arguments[1], arguments[2]); -/** - * Retrieve a subset of a string - * @param {String} str String from which to get a substring - * @param {Array[] | Range[] | Number[] | Matrix} index - * Two dimensional array (size 1 x n) containing - * the indexes to be retrieved. Can also be a two - * dimensional Matrix (size 1 x n), or an Array - * (size 1) containing a Range or a Number. - * @returns {string} substring - * @private - */ -function _getSubstring(str, index) { - var i, len; - index = index.valueOf(); // cast from matrix or range to array - if (index.length != 1) { - throw new RangeError('Dimension mismatch (' + index.length + ' != 1)'); - } + default: // wrong number of arguments + throw new util.error.ArgumentsError('subset', arguments.length, 2, 3); + } + }; - if (Array.isArray(index)) { - index = index[0]; // read first dimension - } - index = index.valueOf(); // cast from matrix or range to array - if (!Array.isArray(index)) { - index = [index]; - } + /** + * Retrieve a subset of an value such as an Array, Matrix, or String + * @param {*} value Object from which to get a subset + * @param {Array[] | Range[] | Number[] | Matrix} index + * Two dimensional array (size 1 x n) containing + * the indexes to be retrieved. Can also be a two + * dimensional Matrix (size 1 x n), or an Array + * (size 1) containing a Range or a Number. + * @returns {*} subset + * @private + */ + function _getSubset(value, index) { + var m, subset; - var substr = ''; - var strLen = str.length; - for (i = 0, len = index.length; i < len; i++) { - var index_i = index[i]; - util.validateIndex(index_i, strLen); - substr += str.charAt(index_i); // index_i is zero based - } - - return substr; -} - -/** - * Replace a subset in an value such as an Array, Matrix, or String - * @param {*} value Object to be replaced - * @param {Array[] | Range[] | Number[] | Matrix} index - * Two dimensional array (size 1 x n) containing - * the indexes to be replaced. Can also be a two - * dimensional Matrix (size 1 x n), or an Array - * (size 1) containing a Range. - * @param {String} replacement - * @returns {*} result - * @private - */ -function _setSubset(value, index, replacement) { - if (Array.isArray(value) || value instanceof Range) { - var matrix = math.matrix(math.clone(value)); - matrix.set(index, replacement); - return matrix.valueOf(); - } - else if (value instanceof Matrix) { - return value.clone().set(index, replacement); - } - else if (isString(value)) { - return _setSubstring(value, index, replacement); - } - else { - // scalar - matrix = math.matrix([value]); - matrix.set(index, replacement); - - if (matrix.isScalar()) { - // still a scalar - return matrix.toScalar(); + if (isArray(value) || value instanceof Range) { + m = new Matrix(value); + subset = m.get(index); + return subset.valueOf(); + } + else if (value instanceof Matrix) { + return value.get(index); + } + else if (isString(value)) { + return _getSubstring(value, index); } else { - // changed into a matrix. return array - return matrix.valueOf(); + // scalar + m = new Matrix([value]); + subset = m.get(index); + return subset.valueOf(); } } -} -/** - * Replace a substring in a string - * @param {String} str String to be replaced - * @param {Array[] | Range[] | Number[] | Matrix} index - * Two dimensional array (size 1 x n) containing - * the indexes to be replaced. Can also be a two - * dimensional Matrix (size 1 x n), or an Array - * (size 1) containing a Range. - * @param {String} replacement Replacement string - * @returns {string} result - * @private - */ -function _setSubstring(str, index, replacement) { - var i, len; - index = index.valueOf(); // cast from matrix or range to array + /** + * Retrieve a subset of a string + * @param {String} str String from which to get a substring + * @param {Array[] | Range[] | Number[] | Matrix} index + * Two dimensional array (size 1 x n) containing + * the indexes to be retrieved. Can also be a two + * dimensional Matrix (size 1 x n), or an Array + * (size 1) containing a Range or a Number. + * @returns {string} substring + * @private + */ + function _getSubstring(str, index) { + var i, len; + index = index.valueOf(); // cast from matrix or range to array + if (index.length != 1) { + throw new RangeError('Dimension mismatch (' + index.length + ' != 1)'); + } - if (index.length != 1) { - throw new RangeError('Dimension mismatch (' + index.length + ' != 1)'); - } - if (Array.isArray(index)) { - index = index[0]; // read first dimension - } - index = index.valueOf(); // cast from matrix or range to array - if (!Array.isArray(index)) { - index = [index]; + if (isArray(index)) { + index = index[0]; // read first dimension + } + index = index.valueOf(); // cast from matrix or range to array + if (!isArray(index)) { + index = [index]; + } + + var substr = ''; + var strLen = str.length; + for (i = 0, len = index.length; i < len; i++) { + var index_i = index[i]; + array.validateIndex(index_i, strLen); + substr += str.charAt(index_i); // index_i is zero based + } + + return substr; } - if (index.length != replacement.length) { - throw new RangeError('Dimension mismatch ' + - '(' + index.length + ' != ' + replacement.length + ')'); - } + /** + * Replace a subset in an value such as an Array, Matrix, or String + * @param {*} value Object to be replaced + * @param {Array[] | Range[] | Number[] | Matrix} index + * Two dimensional array (size 1 x n) containing + * the indexes to be replaced. Can also be a two + * dimensional Matrix (size 1 x n), or an Array + * (size 1) containing a Range. + * @param {String} replacement + * @returns {*} result + * @private + */ + function _setSubset(value, index, replacement) { + if (isArray(value) || value instanceof Range) { + var m = new Matrix(math.clone(value)); + m.set(index, replacement); + return m.valueOf(); + } + else if (value instanceof Matrix) { + return value.clone().set(index, replacement); + } + else if (isString(value)) { + return _setSubstring(value, index, replacement); + } + else { + // scalar + m = new Matrix([value]); + m.set(index, replacement); - // copy the string into an array with characters - var strLen = str.length; - var chars = []; - for (i = 0; i < strLen; i++) { - chars[i] = str.charAt(i); - } - - for (i = 0, len = index.length; i < len; i++) { - var index_i = index[i]; - util.validateIndex(index_i); - chars[index_i] = replacement.charAt(i); // index_i is zero based - } - - // initialize undefined characters with a space - if (chars.length > strLen) { - for (i = strLen - 1, len = chars.length; i < len; i++) { - if (!chars[i]) { - chars[i] = ' '; + if (m.isScalar()) { + // still a scalar + return m.toScalar(); + } + else { + // changed into a matrix. return array + return m.valueOf(); } } } - return chars.join(''); -} + /** + * Replace a substring in a string + * @param {String} str String to be replaced + * @param {Array[] | Range[] | Number[] | Matrix} index + * Two dimensional array (size 1 x n) containing + * the indexes to be replaced. Can also be a two + * dimensional Matrix (size 1 x n), or an Array + * (size 1) containing a Range. + * @param {String} replacement Replacement string + * @returns {string} result + * @private + */ + function _setSubstring(str, index, replacement) { + var i, len; + index = index.valueOf(); // cast from matrix or range to array + + if (index.length != 1) { + throw new RangeError('Dimension mismatch (' + index.length + ' != 1)'); + } + if (isArray(index)) { + index = index[0]; // read first dimension + } + index = index.valueOf(); // cast from matrix or range to array + if (!isArray(index)) { + index = [index]; + } + + if (index.length != replacement.length) { + throw new RangeError('Dimension mismatch ' + + '(' + index.length + ' != ' + replacement.length + ')'); + } + + // copy the string into an array with characters + var strLen = str.length; + var chars = []; + for (i = 0; i < strLen; i++) { + chars[i] = str.charAt(i); + } + + for (i = 0, len = index.length; i < len; i++) { + var index_i = index[i]; + array.validateIndex(index_i); + chars[index_i] = replacement.charAt(i); // index_i is zero based + } + + // initialize undefined characters with a space + if (chars.length > strLen) { + for (i = strLen - 1, len = chars.length; i < len; i++) { + if (!chars[i]) { + chars[i] = ' '; + } + } + } + + return chars.join(''); + } +}; diff --git a/src/function/matrix/transpose.js b/src/function/matrix/transpose.js index 0fdd9b319..89830a7d9 100644 --- a/src/function/matrix/transpose.js +++ b/src/function/matrix/transpose.js @@ -1,53 +1,62 @@ -/** - * Create the transpose of a matrix - * - * transpose(x) - * - * @param {Array | Matrix} x - * @return {Array | Matrix} transpose - */ -math.transpose = function transpose (x) { - if (arguments.length != 1) { - throw newArgumentsError('transpose', arguments.length, 1); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - var size = math.size(x).valueOf(); - switch (size.length) { - case 0: - // scalar - return math.clone(x); - break; + Matrix = require('../../type/Matrix.js'), - case 1: - // vector - // TODO: is it logic to return a 1 dimensional vector itself as transpose? - return math.clone(x); - break; + object = util.object, + string = util.string; - case 2: - // two dimensional array - var rows = size[1], // index 1 is no error - cols = size[0], // index 0 is no error - asMatrix = x instanceof Matrix, - array = x.valueOf(), - transposed = [], - transposedRow, - clone = math.clone; - for (var r = 0; r < rows; r++) { - transposedRow = transposed[r] = []; - for (var c = 0; c < cols; c++) { - transposedRow[c] = clone(array[c][r]); + /** + * Create the transpose of a matrix + * + * transpose(x) + * + * @param {Array | Matrix} x + * @return {Array | Matrix} transpose + */ + math.transpose = function transpose (x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('transpose', arguments.length, 1); + } + + var size = math.size(x).valueOf(); + switch (size.length) { + case 0: + // scalar + return object.clone(x); + break; + + case 1: + // vector + // TODO: is it logic to return a 1 dimensional vector itself as transpose? + return object.clone(x); + break; + + case 2: + // two dimensional array + var rows = size[1], // index 1 is no error + cols = size[0], // index 0 is no error + asMatrix = Matrix.isMatrix(x), + data = x.valueOf(), + transposed = [], + transposedRow, + clone = object.clone; + for (var r = 0; r < rows; r++) { + transposedRow = transposed[r] = []; + for (var c = 0; c < cols; c++) { + transposedRow[c] = clone(data[c][r]); + } } - } - if (cols == 0) { - transposed[0] = []; - } - return asMatrix ? new Matrix(transposed) : transposed; - break; + if (cols == 0) { + transposed[0] = []; + } + return asMatrix ? new Matrix(transposed) : transposed; + break; - default: - // multi dimensional array - throw new RangeError('Matrix must be two dimensional ' + - '(size: ' + math.format(size) + ')'); - } + default: + // multi dimensional array + throw new RangeError('Matrix must be two dimensional ' + + '(size: ' + string.format(size) + ')'); + } + }; }; diff --git a/src/function/matrix/zeros.js b/src/function/matrix/zeros.js index 2f54c2898..99e7b4170 100644 --- a/src/function/matrix/zeros.js +++ b/src/function/matrix/zeros.js @@ -1,26 +1,33 @@ -/** - * create a matrix filled with zeros - * - * zeros(n) - * zeros(m, n) - * zeros([m, n]) - * zeros([m, n, p, ...]) - * - * @param {...Number | Array} size - * @return {Matrix} matrix - */ -math.zeros = function zeros (size) { - var args = util.argsToArray(arguments); +module.exports = function (math) { + var util = require('../../util/index.js'), - if (args.length == 0) { - args = [1, 1]; - } - else if (args.length == 1) { - args[1] = args[0]; - } + Matrix = require('../../type/Matrix.js'), + collection = require('../../type/collection.js'); - // create and size the matrix - var matrix = new Matrix(); - matrix.resize(args); - return matrix; + /** + * create a matrix filled with zeros + * + * zeros(n) + * zeros(m, n) + * zeros([m, n]) + * zeros([m, n, p, ...]) + * + * @param {...Number | Array} size + * @return {Matrix} matrix + */ + math.zeros = function zeros (size) { + var args = collection.argsToArray(arguments); + + if (args.length == 0) { + args = [1, 1]; + } + else if (args.length == 1) { + args[1] = args[0]; + } + + // create and size the matrix + var matrix = new Matrix(); + matrix.resize(args); + return matrix; + }; }; diff --git a/src/function/probability/factorial.js b/src/function/probability/factorial.js index 897b50972..a5e26ebb0 100644 --- a/src/function/probability/factorial.js +++ b/src/function/probability/factorial.js @@ -1,48 +1,58 @@ -/** - * Compute the factorial of a value - * - * x! - * factorial(x) - * - * Factorial only supports an integer value as argument. - * For matrices, the function is evaluated element wise. - * - * @Param {Number | Array | Matrix} x - * @return {Number | Array | Matrix} res - */ -math.factorial = function factorial (x) { - if (arguments.length != 1) { - throw newArgumentsError('factorial', arguments.length, 1); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (isNumber(x)) { - if (!isInteger(x) || x < 0) { - throw new TypeError('Positive integer value expected in function factorial'); + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isInteger = util.number.isInteger, + isCollection = collection.isCollection; + + /** + * Compute the factorial of a value + * + * x! + * factorial(x) + * + * Factorial only supports an integer value as argument. + * For matrices, the function is evaluated element wise. + * + * @Param {Number | Array | Matrix} x + * @return {Number | Array | Matrix} res + */ + math.factorial = function factorial (x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('factorial', arguments.length, 1); } - var value = x, - res = value; - value--; - while (value > 1) { - res *= value; + if (isNumber(x)) { + if (!isInteger(x) || x < 0) { + throw new TypeError('Positive integer value expected in function factorial'); + } + + var value = x, + res = value; value--; + while (value > 1) { + res *= value; + value--; + } + + if (res == 0) { + res = 1; // 0! is per definition 1 + } + + return res; } - if (res == 0) { - res = 1; // 0! is per definition 1 + if (isCollection(x)) { + return collection.map(x, factorial); } - return res; - } + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return factorial(x.valueOf()); + } - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.factorial); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.factorial(x.valueOf()); - } - - throw newUnsupportedTypeError('factorial', x); + throw new util.error.UnsupportedTypeError('factorial', x); + }; }; diff --git a/src/function/probability/random.js b/src/function/probability/random.js index 935de585e..0fb0e67ca 100644 --- a/src/function/probability/random.js +++ b/src/function/probability/random.js @@ -1,158 +1,167 @@ -/** - * Return a random number between 0 and 1 - * - * random() - * - * @return {Number} res - */ +module.exports = function (math) { + var util = require('../../util/index.js'), -// Each distribution is a function that takes no argument and when called returns -// a number between 0 and 1. -var distributions = { + Matrix = require('../../type/Matrix.js'), - uniform: function() { - return Math.random; - }, + isArray = Array.isArray; - // Implementation of normal distribution using Box-Muller transform - // ref : http://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform - // We take : mean = 0.5, standard deviation = 1/6 - // so that 99.7% values are in [0, 1]. - normal: function() { - return function() { - var u1, u2, - picked = -1; - // We reject values outside of the interval [0, 1] - // TODO: check if it is ok to do that? - while (picked < 0 || picked > 1) { - u1 = Math.random(); - u2 = Math.random(); - picked = 1/6 * Math.pow(-2 * Math.log(u1), 0.5) * Math.cos(2 * Math.PI * u2) + 0.5; + /** + * Return a random number between 0 and 1 + * + * random() + * + * @return {Number} res + */ + + // Each distribution is a function that takes no argument and when called returns + // a number between 0 and 1. + var distributions = { + + uniform: function() { + return Math.random; + }, + + // Implementation of normal distribution using Box-Muller transform + // ref : http://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform + // We take : mean = 0.5, standard deviation = 1/6 + // so that 99.7% values are in [0, 1]. + normal: function() { + return function() { + var u1, u2, + picked = -1; + // We reject values outside of the interval [0, 1] + // TODO: check if it is ok to do that? + while (picked < 0 || picked > 1) { + u1 = Math.random(); + u2 = Math.random(); + picked = 1/6 * Math.pow(-2 * Math.log(u1), 0.5) * Math.cos(2 * Math.PI * u2) + 0.5; + } + return picked; } - return picked; } - } -}; + }; -/** - * Create a distribution object. - * @param {String} name Name of a distribution. - * Choose from 'uniform', 'normal'. - * @return {Object} distribution A distribution object containing functions: - * random([size, min, max]) - * randomInt([min, max]) - * pickRandom(array) - */ -math.distribution = function(name) { - if (!distributions.hasOwnProperty(name)) - throw new Error('unknown distribution ' + name); + /** + * Create a distribution object. + * @param {String} name Name of a distribution. + * Choose from 'uniform', 'normal'. + * @return {Object} distribution A distribution object containing functions: + * random([size, min, max]) + * randomInt([min, max]) + * pickRandom(array) + */ + math.distribution = function(name) { + if (!distributions.hasOwnProperty(name)) + throw new Error('unknown distribution ' + name); - var args = Array.prototype.slice.call(arguments, 1), - distribution = distributions[name].apply(this, args); + var args = Array.prototype.slice.call(arguments, 1), + distribution = distributions[name].apply(this, args); - return (function(distribution) { + return (function(distribution) { - // This is the public API for all distributions - var randFunctions = { + // This is the public API for all distributions + var randFunctions = { - random: function(arg1, arg2, arg3) { - var size, min, max - if (arguments.length > 3) { - throw newArgumentsError(funcName, argCount, 0, 3); + random: function(arg1, arg2, arg3) { + var size, min, max + if (arguments.length > 3) { + throw newArgumentsError(funcName, argCount, 0, 3); - // `random(max)` or `random(size)` - } else if (arguments.length === 1) { - if (Object.prototype.toString.call(arg1) === '[object Array]') + // `random(max)` or `random(size)` + } else if (arguments.length === 1) { + if (Object.prototype.toString.call(arg1) === '[object Array]') + size = arg1 + else max = arg1 + // `random(min, max)` or `random(size, max)` + } else if (arguments.length === 2) { + if (Object.prototype.toString.call(arg1) === '[object Array]') + size = arg1 + else { + min = arg1 + max = arg2 + } + // `random(size, min, max)` + } else { size = arg1 - else max = arg1 - // `random(min, max)` or `random(size, max)` - } else if (arguments.length === 2) { - if (Object.prototype.toString.call(arg1) === '[object Array]') - size = arg1 - else { - min = arg1 - max = arg2 + min = arg2 + max = arg3 } - // `random(size, min, max)` - } else { - size = arg1 - min = arg2 - max = arg3 + + if (max === undefined) max = 1; + if (min === undefined) min = 0; + if (size !== undefined) return new Matrix(_randomDataForMatrix(size, min, max, _random)); + else return _random(min, max); + }, + + randomInt: function(arg1, arg2, arg3) { + var size, min, max + if (arguments.length > 3 || arguments.length < 1) + throw newArgumentsError(funcName, argCount, 1, 3); + + // `randomInt(max)` + else if (arguments.length === 1) max = arg1 + // `randomInt(min, max)` or `randomInt(size, max)` + else if (arguments.length === 2) { + if (Object.prototype.toString.call(arg1) === '[object Array]') + size = arg1 + else { + min = arg1 + max = arg2 + } + // `randomInt(size, min, max)` + } else { + size = arg1 + min = arg2 + max = arg3 + } + + if (min === undefined) min = 0; + if (size !== undefined) return new Matrix(_randomDataForMatrix(size, min, max, _randomInt)); + else return _randomInt(min, max); + }, + + pickRandom: function(possibles) { + if (arguments.length !== 1) + throw newArgumentsError('pickRandom', arguments.length, 1); + return possibles[Math.floor(Math.random() * possibles.length)]; } - if (max === undefined) max = 1; - if (min === undefined) min = 0; - if (size !== undefined) return new Matrix(_randomDataForMatrix(size, min, max, _random)); - else return _random(min, max); - }, + }; - randomInt: function(arg1, arg2, arg3) { - var size, min, max - if (arguments.length > 3 || arguments.length < 1) - throw newArgumentsError(funcName, argCount, 1, 3); + var _random = function(min, max) { + return min + distribution() * (max - min); + }; - // `randomInt(max)` - else if (arguments.length === 1) max = arg1 - // `randomInt(min, max)` or `randomInt(size, max)` - else if (arguments.length === 2) { - if (Object.prototype.toString.call(arg1) === '[object Array]') - size = arg1 - else { - min = arg1 - max = arg2 - } - // `randomInt(size, min, max)` + var _randomInt = function(min, max) { + return Math.floor(min + distribution() * (max - min)); + }; + + // This is a function for generating a random matrix recursively. + var _randomDataForMatrix = function(size, min, max, randFunc) { + var data = [], length, i; + size = size.slice(0); + + if (size.length > 1) { + for (i = 0, length = size.shift(); i < length; i++) + data.push(_randomDataForMatrix(size, min, max, randFunc)); } else { - size = arg1 - min = arg2 - max = arg3 + for (i = 0, length = size.shift(); i < length; i++) + data.push(randFunc(min, max)); } - if (min === undefined) min = 0; - if (size !== undefined) return new Matrix(_randomDataForMatrix(size, min, max, _randomInt)); - else return _randomInt(min, max); - }, + return data; + }; - pickRandom: function(possibles) { - if (arguments.length !== 1) - throw newArgumentsError('pickRandom', arguments.length, 1); - return possibles[Math.floor(Math.random() * possibles.length)]; - } + return randFunctions; - }; + })(distribution); - var _random = function(min, max) { - return min + distribution() * (max - min); - }; - - var _randomInt = function(min, max) { - return Math.floor(min + distribution() * (max - min)); - }; - - // This is a function for generating a random matrix recursively. - var _randomDataForMatrix = function(size, min, max, randFunc) { - var data = [], length, i; - size = size.slice(0); - - if (size.length > 1) { - for (i = 0, length = size.shift(); i < length; i++) - data.push(_randomDataForMatrix(size, min, max, randFunc)); - } else { - for (i = 0, length = size.shift(); i < length; i++) - data.push(randFunc(min, max)); - } - - return data; - }; - - return randFunctions; - - })(distribution); + }; + // Default random functions use uniform distribution + // TODO: put random functions in separate files? + var uniformRandFunctions = math.distribution('uniform'); + math.random = uniformRandFunctions.random; + math.randomInt = uniformRandFunctions.randomInt; + math.pickRandom = uniformRandFunctions.pickRandom; }; - -// Default random functions use uniform distribution -var uniformRandFunctions = math.distribution('uniform'); -math.random = uniformRandFunctions.random; -math.randomInt = uniformRandFunctions.randomInt; -math.pickRandom = uniformRandFunctions.pickRandom; diff --git a/src/function/statistics/max.js b/src/function/statistics/max.js index d3d318b9f..cd4614aca 100644 --- a/src/function/statistics/max.js +++ b/src/function/statistics/max.js @@ -1,97 +1,103 @@ -/** - * Compute the maximum value of a list of values - * - * max(a, b, c, ...) - * max([a, b, c, ...]) - * - * @param {... *} args A single matrix or or multiple scalar values - * @return {*} res - */ -math.max = function max(args) { - if (arguments.length == 0) { - throw new Error('Function max requires one or more parameters (0 provided)'); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (Array.isArray(args) || args instanceof Matrix || args instanceof Range) { - // max([a, b, c, d, ...]]) - if (arguments.length > 1) { - throw Error('Wrong number of parameters (1 matrix or multiple scalars expected)'); + Matrix = require('../../type/Matrix.js'), + collection = require('../../type/collection.js'), + + isCollection = collection.isCollection; + + /** + * Compute the maximum value of a list of values + * + * max(a, b, c, ...) + * max([a, b, c, ...]) + * + * @param {... *} args A single matrix or or multiple scalar values + * @return {*} res + */ + math.max = function max(args) { + if (arguments.length == 0) { + throw new Error('Function max requires one or more parameters (0 provided)'); } - var size = math.size(args).valueOf(); - - if (size.length == 1) { - // vector - if (args.length == 0) { - throw new Error('Cannot calculate max of an empty vector'); + if (isCollection(args)) { + // max([a, b, c, d, ...]]) + if (arguments.length > 1) { + throw Error('Wrong number of parameters (1 matrix or multiple scalars expected)'); } - return _max(args.valueOf()); - } - else if (size.length == 2) { - // 2 dimensional matrix - if (size[0] == 0 || size[1] == 0) { - throw new Error('Cannot calculate max of an empty matrix'); + var size = math.size(args).valueOf(); + + if (size.length == 1) { + // vector + if (args.length == 0) { + throw new Error('Cannot calculate max of an empty vector'); + } + + return _max(args.valueOf()); } - if (Array.isArray(args)) { - return _max2(args, size[0], size[1]); - } - else if (args instanceof Matrix || args instanceof Range) { - return new Matrix(_max2(args.valueOf(), size[0], size[1])); + else if (size.length == 2) { + // 2 dimensional matrix + if (size[0] == 0 || size[1] == 0) { + throw new Error('Cannot calculate max of an empty matrix'); + } + + // TODO: make a generic collection method for this + if (Matrix.isMatrix(args)) { + return new Matrix(_max2(args.valueOf(), size[0], size[1])); + } + else { + return _max2(args, size[0], size[1]); + } } else { - throw newUnsupportedTypeError('max', args); + // TODO: implement max for n-dimensional matrices + throw new RangeError('Cannot calculate max for multi dimensional matrix'); } } else { - // TODO: implement max for n-dimensional matrices - throw new RangeError('Cannot calculate max for multi dimensional matrix'); + // max(a, b, c, d, ...) + return _max(arguments); } - } - else { - // max(a, b, c, d, ...) - return _max(arguments); - } -}; + }; -/** - * Calculate the max of a one dimensional array - * @param {Array} array - * @return {Number} max - * @private - */ -function _max(array) { - var larger = math.larger; - var res = array[0]; - for (var i = 1, iMax = array.length; i < iMax; i++) { - var value = array[i]; - if (larger(value, res)) { - res = value; - } - } - return res; -} - -/** - * Calculate the max of a two dimensional array - * @param {Array} array - * @param {Number} rows - * @param {Number} cols - * @return {Number[]} max - * @private - */ -function _max2(array, rows, cols) { - var larger = math.larger; - var res = []; - for (var c = 0; c < cols; c++) { - var max = array[0][c]; - for (var r = 1; r < rows; r++) { - var value = array[r][c]; - if (larger(value, max)) { - max = value; + /** + * Calculate the max of a one dimensional array + * @param {Array} array + * @return {Number} max + * @private + */ + function _max(array) { + var res = array[0]; + for (var i = 1, iMax = array.length; i < iMax; i++) { + var value = array[i]; + if (math.larger(value, res)) { + res = value; } } - res[c] = max; + return res; } - return res; -} + + /** + * Calculate the max of a two dimensional array + * @param {Array} array + * @param {Number} rows + * @param {Number} cols + * @return {Number[]} max + * @private + */ + function _max2(array, rows, cols) { + var res = []; + for (var c = 0; c < cols; c++) { + var max = array[0][c]; + for (var r = 1; r < rows; r++) { + var value = array[r][c]; + if (math.larger(value, max)) { + max = value; + } + } + res[c] = max; + } + return res; + } +}; diff --git a/src/function/statistics/min.js b/src/function/statistics/min.js index 1904aef5b..a1260a079 100644 --- a/src/function/statistics/min.js +++ b/src/function/statistics/min.js @@ -1,97 +1,103 @@ -/** - * Compute the minimum value of a list of values - * - * min(a, b, c, ...) - * min([a, b, c, ...]) - * - * @param {... *} args A single matrix or multiple scalars - * @return {*} res - */ -math.min = function min(args) { - if (arguments.length == 0) { - throw new Error('Function min requires one or more parameters (0 provided)'); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (Array.isArray(args) || args instanceof Matrix || args instanceof Range) { - // min([a, b, c, d, ...]]) - if (arguments.length > 1) { - throw Error('Wrong number of parameters (1 matrix or multiple scalars expected)'); + Matrix = require('../../type/Matrix.js'), + collection = require('../../type/collection.js'), + + isCollection = collection.isCollection; + + /** + * Compute the minimum value of a list of values + * + * min(a, b, c, ...) + * min([a, b, c, ...]) + * + * @param {... *} args A single matrix or multiple scalars + * @return {*} res + */ + math.min = function min(args) { + if (arguments.length == 0) { + throw new Error('Function min requires one or more parameters (0 provided)'); } - var size = math.size(args).valueOf(); - - if (size.length == 1) { - // vector - if (args.length == 0) { - throw new Error('Cannot calculate min of an empty vector'); + if (isCollection(args)) { + // min([a, b, c, d, ...]]) + if (arguments.length > 1) { + throw Error('Wrong number of parameters (1 matrix or multiple scalars expected)'); } - return _min(args.valueOf()); - } - else if (size.length == 2) { - // 2 dimensional matrix - if (size[0] == 0 || size[1] == 0) { - throw new Error('Cannot calculate min of an empty matrix'); + var size = math.size(args).valueOf(); + + if (size.length == 1) { + // vector + if (args.length == 0) { + throw new Error('Cannot calculate min of an empty vector'); + } + + return _min(args.valueOf()); } - if (Array.isArray(args)) { - return _min2(args, size[0], size[1]); - } - else if (args instanceof Matrix || args instanceof Range) { - return new Matrix(_min2(args.valueOf(), size[0], size[1])); + else if (size.length == 2) { + // 2 dimensional matrix + if (size[0] == 0 || size[1] == 0) { + throw new Error('Cannot calculate min of an empty matrix'); + } + + // TODO: make a generic collection method for this + if (Matrix.isMatrix(args)) { + return new Matrix(_min2(args.valueOf(), size[0], size[1])); + } + else { + return _min2(args, size[0], size[1]); + } } else { - throw newUnsupportedTypeError('min', args); + // TODO: implement min for n-dimensional matrices + throw new RangeError('Cannot calculate min for multi dimensional matrix'); } } else { - // TODO: implement min for n-dimensional matrices - throw new RangeError('Cannot calculate min for multi dimensional matrix'); + // min(a, b, c, d, ...) + return _min(arguments); } - } - else { - // min(a, b, c, d, ...) - return _min(arguments); - } -}; + }; -/** - * Calculate the min of a one dimensional array - * @param {Array} array - * @return {Number} min - * @private - */ -function _min(array) { - var smaller = math.smaller; - var res = array[0]; - for (var i = 1, iMax = array.length; i < iMax; i++) { - var value = array[i]; - if (smaller(value, res)) { - res = value; - } - } - return res; -} - -/** - * Calculate the min of a two dimensional array - * @param {Array} array - * @param {Number} rows - * @param {Number} cols - * @return {Number[]} min - * @private - */ -function _min2(array, rows, cols) { - var smaller = math.smaller; - var res = []; - for (var c = 0; c < cols; c++) { - var min = array[0][c]; - for (var r = 1; r < rows; r++) { - var value = array[r][c]; - if (smaller(value, min)) { - min = value; + /** + * Calculate the min of a one dimensional array + * @param {Array} array + * @return {Number} min + * @private + */ + function _min(array) { + var res = array[0]; + for (var i = 1, iMax = array.length; i < iMax; i++) { + var value = array[i]; + if (math.smaller(value, res)) { + res = value; } } - res[c] = min; + return res; } - return res; -} + + /** + * Calculate the min of a two dimensional array + * @param {Array} array + * @param {Number} rows + * @param {Number} cols + * @return {Number[]} min + * @private + */ + function _min2(array, rows, cols) { + var res = []; + for (var c = 0; c < cols; c++) { + var min = array[0][c]; + for (var r = 1; r < rows; r++) { + var value = array[r][c]; + if (math.smaller(value, min)) { + min = value; + } + } + res[c] = min; + } + return res; + } +}; diff --git a/src/function/trigonometry/acos.js b/src/function/trigonometry/acos.js index fe3c24191..04dfc7757 100644 --- a/src/function/trigonometry/acos.js +++ b/src/function/trigonometry/acos.js @@ -1,74 +1,85 @@ -/** - * Calculate the inverse cosine of a value - * - * acos(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - * - * @see http://mathworld.wolfram.com/InverseCosine.html - */ -math.acos = function acos(x) { - if (arguments.length != 1) { - throw newArgumentsError('acos', arguments.length, 1); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (isNumber(x)) { - if (x >= -1 && x <= 1) { - return Math.acos(x); - } - else { - return math.acos(new Complex(x, 0)); - } - } + Complex = require('../../type/Complex.js'), + collection = require('../../type/collection.js'), - if (x instanceof Complex) { - // acos(z) = 0.5*pi + i*log(iz + sqrt(1-z^2)) - var temp1 = Complex.create( - x.im * x.im - x.re * x.re + 1.0, - -2.0 * x.re * x.im - ); - var temp2 = math.sqrt(temp1); - var temp3; - if (temp2 instanceof Complex) { - temp3 = Complex.create( - temp2.re - x.im, - temp2.im + x.re - ) - } - else { - temp3 = Complex.create( - temp2 - x.im, - x.re - ) - } - var temp4 = math.log(temp3); + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isCollection = collection.isCollection; - // 0.5*pi = 1.5707963267948966192313216916398 - if (temp4 instanceof Complex) { - return Complex.create( - 1.57079632679489661923 - temp4.im, - temp4.re + /** + * Calculate the inverse cosine of a value + * + * acos(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + * + * @see http://mathworld.wolfram.com/InverseCosine.html + */ + math.acos = function acos(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('acos', arguments.length, 1); + } + + if (isNumber(x)) { + if (x >= -1 && x <= 1) { + return Math.acos(x); + } + else { + return acos(new Complex(x, 0)); + } + } + + if (isComplex(x)) { + // acos(z) = 0.5*pi + i*log(iz + sqrt(1-z^2)) + var temp1 = Complex.create( + x.im * x.im - x.re * x.re + 1.0, + -2.0 * x.re * x.im ); + var temp2 = math.sqrt(temp1); + var temp3; + if (temp2 instanceof Complex) { + temp3 = Complex.create( + temp2.re - x.im, + temp2.im + x.re + ) + } + else { + temp3 = Complex.create( + temp2 - x.im, + x.re + ) + } + var temp4 = math.log(temp3); + + // 0.5*pi = 1.5707963267948966192313216916398 + if (temp4 instanceof Complex) { + return Complex.create( + 1.57079632679489661923 - temp4.im, + temp4.re + ); + } + else { + return new Complex( + 1.57079632679489661923, + temp4 + ); + } } - else { - return new Complex( - 1.57079632679489661923, - temp4 - ); + + if (isCollection(x)) { + return collection.map(x, acos); } - } - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.acos); - } + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return acos(x.valueOf()); + } - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.acos(x.valueOf()); - } - - throw newUnsupportedTypeError('acos', x); + throw new util.error.UnsupportedTypeError('acos', x); + }; }; diff --git a/src/function/trigonometry/asin.js b/src/function/trigonometry/asin.js index 8f8d22c20..97a24ac17 100644 --- a/src/function/trigonometry/asin.js +++ b/src/function/trigonometry/asin.js @@ -1,71 +1,82 @@ -/** - * Calculate the inverse sine of a value - * - * asin(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - * - * @see http://mathworld.wolfram.com/InverseSine.html - */ -math.asin = function asin(x) { - if (arguments.length != 1) { - throw newArgumentsError('asin', arguments.length, 1); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (isNumber(x)) { - if (x >= -1 && x <= 1) { - return Math.asin(x); + Complex = require('../../type/Complex.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isCollection = collection.isCollection; + + /** + * Calculate the inverse sine of a value + * + * asin(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + * + * @see http://mathworld.wolfram.com/InverseSine.html + */ + math.asin = function asin(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('asin', arguments.length, 1); } - else { - return math.asin(new Complex(x, 0)); + + if (isNumber(x)) { + if (x >= -1 && x <= 1) { + return Math.asin(x); + } + else { + return asin(new Complex(x, 0)); + } } - } - if (x instanceof Complex) { - // asin(z) = -i*log(iz + sqrt(1-z^2)) - var re = x.re; - var im = x.im; - var temp1 = Complex.create( - im * im - re * re + 1.0, - -2.0 * re * im - ); - - var temp2 = math.sqrt(temp1); - var temp3; - if (temp2 instanceof Complex) { - temp3 = Complex.create( - temp2.re - im, - temp2.im + re - ); - } - else { - temp3 = Complex.create( - temp2 - im, - re + if (isComplex(x)) { + // asin(z) = -i*log(iz + sqrt(1-z^2)) + var re = x.re; + var im = x.im; + var temp1 = Complex.create( + im * im - re * re + 1.0, + -2.0 * re * im ); + + var temp2 = math.sqrt(temp1); + var temp3; + if (temp2 instanceof Complex) { + temp3 = Complex.create( + temp2.re - im, + temp2.im + re + ); + } + else { + temp3 = Complex.create( + temp2 - im, + re + ); + } + + var temp4 = math.log(temp3); + + if (temp4 instanceof Complex) { + return Complex.create(temp4.im, -temp4.re); + } + else { + return Complex.create(0, -temp4); + } } - var temp4 = math.log(temp3); - - if (temp4 instanceof Complex) { - return Complex.create(temp4.im, -temp4.re); + if (isCollection(x)) { + return collection.map(x, asin); } - else { - return Complex.create(0, -temp4); + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return asin(x.valueOf()); } - } - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.asin); - } - - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.asin(x.valueOf()); - } - - throw newUnsupportedTypeError('asin', x); + throw new util.error.UnsupportedTypeError('asin', x); + }; }; diff --git a/src/function/trigonometry/atan.js b/src/function/trigonometry/atan.js index 6c333fcfb..98bd03f49 100644 --- a/src/function/trigonometry/atan.js +++ b/src/function/trigonometry/atan.js @@ -1,58 +1,69 @@ -/** - * Calculate the inverse tangent of a value - * - * atan(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - * - * @see http://mathworld.wolfram.com/InverseTangent.html - */ -math.atan = function atan(x) { - if (arguments.length != 1) { - throw newArgumentsError('atan', arguments.length, 1); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (isNumber(x)) { - return Math.atan(x); - } + Complex = require('../../type/Complex.js'), + collection = require('../../type/collection.js'), - if (x instanceof Complex) { - // atan(z) = 1/2 * i * (ln(1-iz) - ln(1+iz)) - var re = x.re; - var im = x.im; - var den = re * re + (1.0 - im) * (1.0 - im); + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isCollection = collection.isCollection; - var temp1 = Complex.create( - (1.0 - im * im - re * re) / den, - (-2.0 * re) / den - ); - var temp2 = math.log(temp1); - - if (temp2 instanceof Complex) { - return Complex.create( - -0.5 * temp2.im, - 0.5 * temp2.re - ); + /** + * Calculate the inverse tangent of a value + * + * atan(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + * + * @see http://mathworld.wolfram.com/InverseTangent.html + */ + math.atan = function atan(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('atan', arguments.length, 1); } - else { - return Complex.create( - 0, - 0.5 * temp2 - ); + + if (isNumber(x)) { + return Math.atan(x); } - } - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.atan); - } + if (isComplex(x)) { + // atan(z) = 1/2 * i * (ln(1-iz) - ln(1+iz)) + var re = x.re; + var im = x.im; + var den = re * re + (1.0 - im) * (1.0 - im); - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.atan(x.valueOf()); - } + var temp1 = Complex.create( + (1.0 - im * im - re * re) / den, + (-2.0 * re) / den + ); + var temp2 = math.log(temp1); - throw newUnsupportedTypeError('atan', x); + if (temp2 instanceof Complex) { + return Complex.create( + -0.5 * temp2.im, + 0.5 * temp2.re + ); + } + else { + return Complex.create( + 0, + 0.5 * temp2 + ); + } + } + + if (isCollection(x)) { + return collection.map(x, atan); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return atan(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('atan', x); + }; }; diff --git a/src/function/trigonometry/atan2.js b/src/function/trigonometry/atan2.js index 488483937..16bbbf4e0 100644 --- a/src/function/trigonometry/atan2.js +++ b/src/function/trigonometry/atan2.js @@ -1,51 +1,61 @@ -/** - * Computes the principal value of the arc tangent of y/x in radians - * - * atan2(y, x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Array | Matrix} y - * @param {Number | Complex | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - * - * @see http://mathworld.wolfram.com/InverseTangent.html - */ -math.atan2 = function atan2(y, x) { - if (arguments.length != 2) { - throw newArgumentsError('atan2', arguments.length, 2); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (isNumber(y)) { - if (isNumber(x)) { - return Math.atan2(y, x); + Complex = require('../../type/Complex.js'), + collection = require('../../type/collection.js'), + + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isCollection = collection.isCollection; + + /** + * Computes the principal value of the arc tangent of y/x in radians + * + * atan2(y, x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Array | Matrix} y + * @param {Number | Complex | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + * + * @see http://mathworld.wolfram.com/InverseTangent.html + */ + math.atan2 = function atan2(y, x) { + if (arguments.length != 2) { + throw new util.error.ArgumentsError('atan2', arguments.length, 2); } - /* TODO: support for complex computation of atan2 - else if (x instanceof Complex) { - return Math.atan2(y.re, x.re); - } - */ - } - else if (y instanceof Complex) { - if (isNumber(x)) { - return Math.atan2(y.re, x); + + if (isNumber(y)) { + if (isNumber(x)) { + return Math.atan2(y, x); + } + /* TODO: support for complex computation of atan2 + else if (isComplex(x)) { + return Math.atan2(y.re, x.re); + } + */ + } + else if (isComplex(y)) { + if (isNumber(x)) { + return Math.atan2(y.re, x); + } + /* TODO: support for complex computation of atan2 + else if (isComplex(x)) { + return Math.atan2(y.re, x.re); + } + */ } - /* TODO: support for complex computation of atan2 - else if (x instanceof Complex) { - return Math.atan2(y.re, x.re); - } - */ - } - if (Array.isArray(y) || y instanceof Matrix || - Array.isArray(x) || x instanceof Matrix) { - return util.map2(y, x, math.atan2); - } + if (isCollection(y) || isCollection(x)) { + return collection.map2(y, x, atan2); + } - if (x.valueOf() !== x || y.valueOf() !== y) { - // fallback on the objects primitive values - return math.atan2(y.valueOf(), x.valueOf()); - } + if (x.valueOf() !== x || y.valueOf() !== y) { + // fallback on the objects primitive values + return atan2(y.valueOf(), x.valueOf()); + } - throw newUnsupportedTypeError('atan2', y, x); + throw new util.error.UnsupportedTypeError('atan2', y, x); + }; }; diff --git a/src/function/trigonometry/cos.js b/src/function/trigonometry/cos.js index 4e80c03a5..52f5b2713 100644 --- a/src/function/trigonometry/cos.js +++ b/src/function/trigonometry/cos.js @@ -1,47 +1,60 @@ -/** - * Calculate the cosine of a value - * - * cos(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Unit | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - * - * @see http://mathworld.wolfram.com/Cosine.html - */ -math.cos = function cos(x) { - if (arguments.length != 1) { - throw newArgumentsError('cos', arguments.length, 1); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (isNumber(x)) { - return Math.cos(x); - } + Complex = require('../../type/Complex.js'), + Unit = require('../../type/Unit.js'), + collection = require('../../type/collection.js'), - if (x instanceof Complex) { - // cos(z) = (exp(iz) + exp(-iz)) / 2 - return Complex.create( - 0.5 * Math.cos(x.re) * (Math.exp(-x.im) + Math.exp(x.im)), - 0.5 * Math.sin(x.re) * (Math.exp(-x.im) - Math.exp(x.im)) - ); - } + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isUnit = Unit.isUnit, + isCollection = collection.isCollection; - if (x instanceof Unit) { - if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function cos is no angle'); + /** + * Calculate the cosine of a value + * + * cos(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Unit | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + * + * @see http://mathworld.wolfram.com/Cosine.html + */ + math.cos = function cos(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('cos', arguments.length, 1); } - return Math.cos(x.value); - } - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.cos); - } + if (isNumber(x)) { + return Math.cos(x); + } - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.cos(x.valueOf()); - } + if (isComplex(x)) { + // cos(z) = (exp(iz) + exp(-iz)) / 2 + return Complex.create( + 0.5 * Math.cos(x.re) * (Math.exp(-x.im) + Math.exp(x.im)), + 0.5 * Math.sin(x.re) * (Math.exp(-x.im) - Math.exp(x.im)) + ); + } - throw newUnsupportedTypeError('cos', x); + if (isUnit(x)) { + if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) { + throw new TypeError ('Unit in function cos is no angle'); + } + return Math.cos(x.value); + } + + if (isCollection(x)) { + return collection.map(x, cos); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return cos(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('cos', x); + }; }; diff --git a/src/function/trigonometry/cot.js b/src/function/trigonometry/cot.js index 1cb171346..b111218aa 100644 --- a/src/function/trigonometry/cot.js +++ b/src/function/trigonometry/cot.js @@ -1,47 +1,60 @@ -/** - * Calculate the cotangent of a value. cot(x) is defined as 1 / tan(x) - * - * cot(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Unit | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ -math.cot = function cot(x) { - if (arguments.length != 1) { - throw newArgumentsError('cot', arguments.length, 1); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (isNumber(x)) { - return 1 / Math.tan(x); - } + Complex = require('../../type/Complex.js'), + Unit = require('../../type/Unit.js'), + collection = require('../../type/collection.js'), - if (x instanceof Complex) { - var den = Math.exp(-4.0 * x.im) - - 2.0 * Math.exp(-2.0 * x.im) * Math.cos(2.0 * x.re) + 1.0; + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isUnit = Unit.isUnit, + isCollection = collection.isCollection; - return Complex.create( - 2.0 * Math.exp(-2.0 * x.im) * Math.sin(2.0 * x.re) / den, - (Math.exp(-4.0 * x.im) - 1.0) / den - ); - } - - if (x instanceof Unit) { - if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function cot is no angle'); + /** + * Calculate the cotangent of a value. cot(x) is defined as 1 / tan(x) + * + * cot(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Unit | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + */ + math.cot = function cot(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('cot', arguments.length, 1); } - return 1 / Math.tan(x.value); - } - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.cot); - } + if (isNumber(x)) { + return 1 / Math.tan(x); + } - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.cot(x.valueOf()); - } + if (isComplex(x)) { + var den = Math.exp(-4.0 * x.im) - + 2.0 * Math.exp(-2.0 * x.im) * Math.cos(2.0 * x.re) + 1.0; - throw newUnsupportedTypeError('cot', x); + return Complex.create( + 2.0 * Math.exp(-2.0 * x.im) * Math.sin(2.0 * x.re) / den, + (Math.exp(-4.0 * x.im) - 1.0) / den + ); + } + + if (isUnit(x)) { + if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) { + throw new TypeError ('Unit in function cot is no angle'); + } + return 1 / Math.tan(x.value); + } + + if (isCollection(x)) { + return collection.map(x, cot); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return cot(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('cot', x); + }; }; diff --git a/src/function/trigonometry/csc.js b/src/function/trigonometry/csc.js index 3c7e3fefd..46071407c 100644 --- a/src/function/trigonometry/csc.js +++ b/src/function/trigonometry/csc.js @@ -1,48 +1,61 @@ -/** - * Calculate the cosecant of a value, csc(x) = 1/sin(x) - * - * csc(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Unit | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ -math.csc = function csc(x) { - if (arguments.length != 1) { - throw newArgumentsError('csc', arguments.length, 1); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (isNumber(x)) { - return 1 / Math.sin(x); - } + Complex = require('../../type/Complex.js'), + Unit = require('../../type/Unit.js'), + collection = require('../../type/collection.js'), - if (x instanceof Complex) { - // csc(z) = 1/sin(z) = (2i) / (exp(iz) - exp(-iz)) - var den = 0.25 * (Math.exp(-2.0 * x.im) + Math.exp(2.0 * x.im)) - - 0.5 * Math.cos(2.0 * x.re); + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isUnit = Unit.isUnit, + isCollection = collection.isCollection; - return Complex.create ( - 0.5 * Math.sin(x.re) * (Math.exp(-x.im) + Math.exp(x.im)) / den, - 0.5 * Math.cos(x.re) * (Math.exp(-x.im) - Math.exp(x.im)) / den - ); - } - - if (x instanceof Unit) { - if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function csc is no angle'); + /** + * Calculate the cosecant of a value, csc(x) = 1/sin(x) + * + * csc(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Unit | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + */ + math.csc = function csc(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('csc', arguments.length, 1); } - return 1 / Math.sin(x.value); - } - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.csc); - } + if (isNumber(x)) { + return 1 / Math.sin(x); + } - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.csc(x.valueOf()); - } + if (isComplex(x)) { + // csc(z) = 1/sin(z) = (2i) / (exp(iz) - exp(-iz)) + var den = 0.25 * (Math.exp(-2.0 * x.im) + Math.exp(2.0 * x.im)) - + 0.5 * Math.cos(2.0 * x.re); - throw newUnsupportedTypeError('csc', x); + return Complex.create ( + 0.5 * Math.sin(x.re) * (Math.exp(-x.im) + Math.exp(x.im)) / den, + 0.5 * Math.cos(x.re) * (Math.exp(-x.im) - Math.exp(x.im)) / den + ); + } + + if (isUnit(x)) { + if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) { + throw new TypeError ('Unit in function csc is no angle'); + } + return 1 / Math.sin(x.value); + } + + if (isCollection(x)) { + return collection.map(x, csc); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return csc(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('csc', x); + }; }; diff --git a/src/function/trigonometry/sec.js b/src/function/trigonometry/sec.js index 495bdb784..257407c97 100644 --- a/src/function/trigonometry/sec.js +++ b/src/function/trigonometry/sec.js @@ -1,47 +1,60 @@ -/** - * Calculate the secant of a value, sec(x) = 1/cos(x) - * - * sec(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Unit | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - */ -math.sec = function sec(x) { - if (arguments.length != 1) { - throw newArgumentsError('sec', arguments.length, 1); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (isNumber(x)) { - return 1 / Math.cos(x); - } + Complex = require('../../type/Complex.js'), + Unit = require('../../type/Unit.js'), + collection = require('../../type/collection.js'), - if (x instanceof Complex) { - // sec(z) = 1/cos(z) = 2 / (exp(iz) + exp(-iz)) - var den = 0.25 * (Math.exp(-2.0 * x.im) + Math.exp(2.0 * x.im)) + - 0.5 * Math.cos(2.0 * x.re); - return Complex.create( - 0.5 * Math.cos(x.re) * (Math.exp(-x.im) + Math.exp( x.im)) / den, - 0.5 * Math.sin(x.re) * (Math.exp( x.im) - Math.exp(-x.im)) / den - ); - } + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isUnit = Unit.isUnit, + isCollection = collection.isCollection; - if (x instanceof Unit) { - if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function sec is no angle'); + /** + * Calculate the secant of a value, sec(x) = 1/cos(x) + * + * sec(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Unit | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + */ + math.sec = function sec(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('sec', arguments.length, 1); } - return 1 / Math.cos(x.value); - } - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.sec); - } + if (isNumber(x)) { + return 1 / Math.cos(x); + } - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.sec(x.valueOf()); - } + if (isComplex(x)) { + // sec(z) = 1/cos(z) = 2 / (exp(iz) + exp(-iz)) + var den = 0.25 * (Math.exp(-2.0 * x.im) + Math.exp(2.0 * x.im)) + + 0.5 * Math.cos(2.0 * x.re); + return Complex.create( + 0.5 * Math.cos(x.re) * (Math.exp(-x.im) + Math.exp( x.im)) / den, + 0.5 * Math.sin(x.re) * (Math.exp( x.im) - Math.exp(-x.im)) / den + ); + } - throw newUnsupportedTypeError('sec', x); + if (isUnit(x)) { + if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) { + throw new TypeError ('Unit in function sec is no angle'); + } + return 1 / Math.cos(x.value); + } + + if (isCollection(x)) { + return collection.map(x, sec); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return sec(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('sec', x); + }; }; diff --git a/src/function/trigonometry/sin.js b/src/function/trigonometry/sin.js index 124d66e7a..09dd5545d 100644 --- a/src/function/trigonometry/sin.js +++ b/src/function/trigonometry/sin.js @@ -1,46 +1,59 @@ -/** - * Calculate the sine of a value - * - * sin(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Unit | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - * - * @see http://mathworld.wolfram.com/Sine.html - */ -math.sin = function sin(x) { - if (arguments.length != 1) { - throw newArgumentsError('sin', arguments.length, 1); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (isNumber(x)) { - return Math.sin(x); - } + Complex = require('../../type/Complex.js'), + Unit = require('../../type/Unit.js'), + collection = require('../../type/collection.js'), - if (x instanceof Complex) { - return Complex.create( - 0.5 * Math.sin(x.re) * (Math.exp(-x.im) + Math.exp( x.im)), - 0.5 * Math.cos(x.re) * (Math.exp( x.im) - Math.exp(-x.im)) - ); - } + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isUnit = Unit.isUnit, + isCollection = collection.isCollection; - if (x instanceof Unit) { - if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function cos is no angle'); + /** + * Calculate the sine of a value + * + * sin(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Unit | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + * + * @see http://mathworld.wolfram.com/Sine.html + */ + math.sin = function sin(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('sin', arguments.length, 1); } - return Math.sin(x.value); - } - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.sin); - } + if (isNumber(x)) { + return Math.sin(x); + } - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.sin(x.valueOf()); - } + if (isComplex(x)) { + return Complex.create( + 0.5 * Math.sin(x.re) * (Math.exp(-x.im) + Math.exp( x.im)), + 0.5 * Math.cos(x.re) * (Math.exp( x.im) - Math.exp(-x.im)) + ); + } - throw newUnsupportedTypeError('sin', x); + if (isUnit(x)) { + if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) { + throw new TypeError ('Unit in function cos is no angle'); + } + return Math.sin(x.value); + } + + if (isCollection(x)) { + return collection.map(x, sin); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return sin(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('sin', x); + }; }; diff --git a/src/function/trigonometry/tan.js b/src/function/trigonometry/tan.js index fa661979f..fb34aae16 100644 --- a/src/function/trigonometry/tan.js +++ b/src/function/trigonometry/tan.js @@ -1,50 +1,63 @@ -/** - * Calculate the tangent of a value - * - * tan(x) - * - * For matrices, the function is evaluated element wise. - * - * @param {Number | Complex | Unit | Array | Matrix} x - * @return {Number | Complex | Array | Matrix} res - * - * @see http://mathworld.wolfram.com/Tangent.html - */ -math.tan = function tan(x) { - if (arguments.length != 1) { - throw newArgumentsError('tan', arguments.length, 1); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (isNumber(x)) { - return Math.tan(x); - } + Complex = require('../../type/Complex.js'), + Unit = require('../../type/Unit.js'), + collection = require('../../type/collection.js'), - if (x instanceof Complex) { - var den = Math.exp(-4.0 * x.im) + - 2.0 * Math.exp(-2.0 * x.im) * Math.cos(2.0 * x.re) + - 1.0; + isNumber = util.number.isNumber, + isComplex = Complex.isComplex, + isUnit = Unit.isUnit, + isCollection = collection.isCollection; - return Complex.create( - 2.0 * Math.exp(-2.0 * x.im) * Math.sin(2.0 * x.re) / den, - (1.0 - Math.exp(-4.0 * x.im)) / den - ); - } - - if (x instanceof Unit) { - if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function tan is no angle'); + /** + * Calculate the tangent of a value + * + * tan(x) + * + * For matrices, the function is evaluated element wise. + * + * @param {Number | Complex | Unit | Array | Matrix} x + * @return {Number | Complex | Array | Matrix} res + * + * @see http://mathworld.wolfram.com/Tangent.html + */ + math.tan = function tan(x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('tan', arguments.length, 1); } - return Math.tan(x.value); - } - if (Array.isArray(x) || x instanceof Matrix) { - return util.map(x, math.tan); - } + if (isNumber(x)) { + return Math.tan(x); + } - if (x.valueOf() !== x) { - // fallback on the objects primitive value - return math.tan(x.valueOf()); - } + if (isComplex(x)) { + var den = Math.exp(-4.0 * x.im) + + 2.0 * Math.exp(-2.0 * x.im) * Math.cos(2.0 * x.re) + + 1.0; - throw newUnsupportedTypeError('tan', x); + return Complex.create( + 2.0 * Math.exp(-2.0 * x.im) * Math.sin(2.0 * x.re) / den, + (1.0 - Math.exp(-4.0 * x.im)) / den + ); + } + + if (isUnit(x)) { + if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) { + throw new TypeError ('Unit in function tan is no angle'); + } + return Math.tan(x.value); + } + + if (isCollection(x)) { + return collection.map(x, tan); + } + + if (x.valueOf() !== x) { + // fallback on the objects primitive value + return tan(x.valueOf()); + } + + throw new util.error.UnsupportedTypeError('tan', x); + }; }; diff --git a/src/function/units/in.js b/src/function/units/in.js index ea2fee265..bd4f9c153 100644 --- a/src/function/units/in.js +++ b/src/function/units/in.js @@ -1,37 +1,47 @@ -/** - * Change the unit of a value. - * - * x in unit - * in(x, unit) - * - * For matrices, the function is evaluated element wise. - * - * @param {Unit | Array | Matrix} x - * @param {Unit | Array | Matrix} unit - * @return {Unit | Array | Matrix} res - */ -math['in'] = function unit_in(x, unit) { - if (arguments.length != 2) { - throw newArgumentsError('in', arguments.length, 2); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - if (x instanceof Unit) { - if (unit instanceof Unit || isString(unit)) { - return x['in'](unit); + Unit = require('../../type/Unit.js'), + collection = require('../../type/collection.js'), + + isString = util.string.isString, + isUnit = Unit.isUnit, + isCollection = collection.isCollection; + + /** + * Change the unit of a value. + * + * x in unit + * in(x, unit) + * + * For matrices, the function is evaluated element wise. + * + * @param {Unit | Array | Matrix} x + * @param {Unit | Array | Matrix} unit + * @return {Unit | Array | Matrix} res + */ + math['in'] = function unit_in(x, unit) { + if (arguments.length != 2) { + throw new util.error.ArgumentsError('in', arguments.length, 2); } - } - // TODO: add support for string, in that case, convert to unit + if (isUnit(x)) { + if (isUnit(unit) || isString(unit)) { + return x['in'](unit); + } + } - if (Array.isArray(x) || x instanceof Matrix || - Array.isArray(unit) || unit instanceof Matrix) { - return util.map2(x, unit, math['in']); - } + // TODO: add support for string, in that case, convert to unit - if (x.valueOf() !== x || unit.valueOf() !== unit) { - // fallback on the objects primitive value - return math['in'](x.valueOf(), unit.valueOf()); - } + if (isCollection(x) || isCollection(unit)) { + return collection.map2(x, unit, unit_in); + } - throw newUnsupportedTypeError('in', x, unit); + if (x.valueOf() !== x || unit.valueOf() !== unit) { + // fallback on the objects primitive value + return unit_in(x.valueOf(), unit.valueOf()); + } + + throw new util.error.UnsupportedTypeError('in', x, unit); + }; }; diff --git a/src/function/utils/clone.js b/src/function/utils/clone.js index f83931e1c..45cc62b6c 100644 --- a/src/function/utils/clone.js +++ b/src/function/utils/clone.js @@ -1,39 +1,20 @@ -/** - * Clone an object - * - * clone(x) - * - * @param {*} x - * @return {*} clone - */ -math.clone = function clone(x) { - if (arguments.length != 1) { - throw newArgumentsError('clone', arguments.length, 1); - } +module.exports = function (math) { + var util = require('../../util/index.js'), + object = util.object; - if (x == null) { - // null or undefined - return x; - } + /** + * Clone an object + * + * clone(x) + * + * @param {*} x + * @return {*} clone + */ + math.clone = function clone (x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('clone', arguments.length, 1); + } - if (typeof(x.clone) === 'function') { - return x.clone(); - } - - if (isNumber(x) || isString(x) || isBoolean(x)) { - return x; - } - - if (Array.isArray(x)) { - var c = math.clone; - return x.map(function (value) { - return c(value); - }); - } - - if (x instanceof Object) { - return util.mapObject(x, math.clone); - } - - throw newUnsupportedTypeError('clone', x); + return object.clone(x); + }; }; diff --git a/src/function/utils/eval.js b/src/function/utils/eval.js index f1d700f37..04616a5bc 100644 --- a/src/function/utils/eval.js +++ b/src/function/utils/eval.js @@ -1,61 +1,72 @@ -/** - * Evaluate an expression. - * - * Syntax: - * - * math.eval(expr) - * math.eval(expr, scope) - * math.eval([expr1, expr2, expr3, ...]) - * math.eval([expr1, expr2, expr3, ...], scope) - * - * Example: - * - * math.eval('(2+3)/4'); // 1.25 - * math.eval('sqrt(3^2 + 4^2)'); // 5 - * math.eval('sqrt(-4)'); // 2i - * math.eval(['a=3', 'b=4', 'a*b']);, // [3, 4, 12] - * - * var scope = {a:3, b:4}; - * math.eval('a * b', scope); // 12 - * - * @param {String | String[] | Matrix} expr - * @param {math.expr.Scope | Object} [scope] - * @return {*} res - * @throws {Error} - */ -math.eval = function (expr, scope) { - if (arguments.length != 1 && arguments.length != 2) { - throw newArgumentsError('eval', arguments.length, 1, 2); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - // instantiate a scope - var evalScope; - if (scope) { - if (scope instanceof math.expr.Scope) { - evalScope = scope; + Scope = require('../../expr/Scope.js'), + + collection = require('../../type/collection.js'), + + isString = util.string.isString, + isCollection = collection.isCollection; + + /** + * Evaluate an expression. + * + * Syntax: + * + * math.eval(expr) + * math.eval(expr, scope) + * math.eval([expr1, expr2, expr3, ...]) + * math.eval([expr1, expr2, expr3, ...], scope) + * + * Example: + * + * math.eval('(2+3)/4'); // 1.25 + * math.eval('sqrt(3^2 + 4^2)'); // 5 + * math.eval('sqrt(-4)'); // 2i + * math.eval(['a=3', 'b=4', 'a*b']);, // [3, 4, 12] + * + * var scope = {a:3, b:4}; + * math.eval('a * b', scope); // 12 + * + * @param {String | String[] | Matrix} expr + * @param {Scope | Object} [scope] + * @return {*} res + * @throws {Error} + */ + math.eval = function _eval (expr, scope) { + if (arguments.length != 1 && arguments.length != 2) { + throw new util.error.ArgumentsError('eval', arguments.length, 1, 2); + } + + // instantiate a scope + var evalScope; + if (scope) { + if (scope instanceof Scope) { + evalScope = scope; + } + else { + evalScope = new Scope(scope); + } } else { - evalScope = new math.expr.Scope(scope); + evalScope = new Scope(); } - } - else { - evalScope = new math.expr.Scope(); - } - if (isString(expr)) { - // evaluate a single expression - var node = math.parse(expr, evalScope); - return node.eval(); - } - else if (Array.isArray(expr) || expr instanceof Matrix) { - // evaluate an array or matrix with expressions - return util.map(expr, function (elem) { - var node = math.parse(elem, evalScope); + if (isString(expr)) { + // evaluate a single expression + var node = math.parse(expr, evalScope); return node.eval(); - }); - } - else { - // oops - throw new TypeError('String or matrix expected'); - } + } + else if (isCollection(expr)) { + // evaluate an array or matrix with expressions + return collection.map(expr, function (elem) { + var node = math.parse(elem, evalScope); + return node.eval(); + }); + } + else { + // oops + throw new TypeError('String or matrix expected'); + } + }; }; diff --git a/src/function/utils/format.js b/src/function/utils/format.js index 28aedfc5a..f6c5263c6 100644 --- a/src/function/utils/format.js +++ b/src/function/utils/format.js @@ -1,67 +1,32 @@ -/** - * Format a value of any type into a string. Interpolate values into the string. - * Numbers are rounded off to a maximum number of 5 digits by default. - * Usage: - * math.format(value) - * math.format(template, object) - * - * Example usage: - * math.format(2/7); // '0.28571' - * math.format(new Complex(2, 3)); // '2 + 3i' - * math.format('Hello $name! The date is $date', { +module.exports = function (math) { + var util = require('../../util/index.js'), + string = util.string; + + /** + * Format a value of any type into a string. Interpolate values into the string. + * Numbers are rounded off to a maximum number of 5 digits by default. + * Usage: + * math.format(value) + * math.format(template, object) + * + * Example usage: + * math.format(2/7); // '0.28571' + * math.format(new Complex(2, 3)); // '2 + 3i' + * math.format('Hello $name! The date is $date', { * name: 'user', * date: new Date().toISOString().substring(0, 10) * }); // 'hello user! The date is 2013-03-23' - * - * @param {String} template - * @param {Object} values - * @return {String} str - */ -math.format = function format(template, values) { - var num = arguments.length; - if (num != 1 && num != 2) { - throw newArgumentsError('format', num, 1, 2); - } - - if (num == 1) { - // just format a value as string - var value = arguments[0]; - if (isNumber(value)) { - return util.formatNumber(value, math.options.precision); + * + * @param {String} template + * @param {Object} values + * @return {String} str + */ + math.format = function format (template, values) { + var num = arguments.length; + if (num != 1 && num != 2) { + throw new util.error.ArgumentsError('format', num, 1, 2); } - if (Array.isArray(value)) { - return util.formatArray(value); - } - - if (isString(value)) { - return '"' + value + '"'; - } - - if (value instanceof Object) { - return value.toString(); - } - - return String(value); - } - else { - if (!isString(template)) { - throw new TypeError('String expected as first parameter in function format'); - } - if (!(values instanceof Object)) { - throw new TypeError('Object expected as first parameter in function format'); - } - - // format values into a string - return template.replace(/\$([\w\.]+)/g, function (original, key) { - var keys = key.split('.'); - var value = values[keys.shift()]; - while (keys.length && value != undefined) { - var k = keys.shift(); - value = k ? value[k] : value + '.'; - } - return value != undefined ? value : original; - } - ); - } + return string.format.apply(string.format, arguments); + }; }; diff --git a/src/function/utils/help.js b/src/function/utils/help.js index 0132ccc8f..8ec358619 100644 --- a/src/function/utils/help.js +++ b/src/function/utils/help.js @@ -1,52 +1,58 @@ -/** - * Retrieve help on a function or data type. - * Help files are retrieved from the documentation in math.docs. - * @param {function | string | Object} search - * @return {Help} help - */ -math.help = function help(search) { - if (arguments.length != 1) { - throw new SyntaxError('Wrong number of arguments in function help ' + - '(' + arguments.length + ' provided, 1 expected)'); - } +module.exports = function (math) { + var util = require('../../util/index.js'), - var text = null; - if ((search instanceof String) || (typeof(search) === 'string')) { - text = search; - } - else { - var prop; - for (prop in math) { - // search in functions and constants - if (math.hasOwnProperty(prop)) { - if (search === math[prop]) { - text = prop; - break; - } - } + Help = require('../../type/Help.js'); + + /** + * Retrieve help on a function or data type. + * Help files are retrieved from the documentation in math.docs. + * @param {function | string | Object} search + * @return {Help} help + */ + math.help = function help(search) { + if (arguments.length != 1) { + throw new SyntaxError('Wrong number of arguments in function help ' + + '(' + arguments.length + ' provided, 1 expected)'); } - if (!text) { - // search data type - for (prop in math.type) { - if (math.type.hasOwnProperty(prop)) { - if (search === math.type[prop]) { + var text = null; + if ((search instanceof String) || (typeof(search) === 'string')) { + text = search; + } + else { + var prop; + for (prop in math) { + // search in functions and constants + if (math.hasOwnProperty(prop)) { + if (search === math[prop]) { text = prop; break; } } } - } - } - if (!text) { - throw new Error('Could not find search term "' + search + '"'); - } - else { - var doc = math.docs[text]; - if (!doc) { - throw new Error('No documentation found on "' + text + '"'); + if (!text) { + // search data type + for (prop in math.type) { + if (math.type.hasOwnProperty(prop)) { + if (search === math.type[prop]) { + text = prop; + break; + } + } + } + } } - return new Help(doc); - } + + if (!text) { + throw new Error('Could not find search term "' + search + '"'); + } + else { + var doc = math.docs[text]; + if (!doc) { + throw new Error('No documentation found on "' + text + '"'); + } + return new Help(doc); + } + }; }; diff --git a/src/function/utils/import.js b/src/function/utils/import.js index 4c9796265..96fb11823 100644 --- a/src/function/utils/import.js +++ b/src/function/utils/import.js @@ -1,109 +1,121 @@ -/** - * Import functions from an object or a file - * @param {function | String | Object} object - * @param {Object} [options] Available options: - * {Boolean} override - * If true, existing functions will be - * overwritten. False by default. - * {Boolean} wrap - * If true (default), the functions will - * be wrapped in a wrapper function which - * converts data types like Matrix to - * primitive data types like Array. - * The wrapper is needed when extending - * math.js with libraries which do not - * support the math.js data types. - */ +module.exports = function (math) { + var util = require('../../util/index.js'), + + Selector = require('../../expr/Selector.js'), + Complex = require('../../type/Complex.js'), + Unit = require('../../type/Unit.js'), + + isNumber = util.number.isNumber, + isString = util.string.isString, + isComplex = Complex.isComplex, + isUnit = Unit.isUnit; + + /** + * Import functions from an object or a file + * @param {function | String | Object} object + * @param {Object} [options] Available options: + * {Boolean} override + * If true, existing functions will be + * overwritten. False by default. + * {Boolean} wrap + * If true (default), the functions will + * be wrapped in a wrapper function which + * converts data types like Matrix to + * primitive data types like Array. + * The wrapper is needed when extending + * math.js with libraries which do not + * support the math.js data types. + */ // TODO: return status information -math['import'] = function math_import(object, options) { - var name; - var opts = { - override: false, - wrap: true + math['import'] = function math_import(object, options) { + var name; + var opts = { + override: false, + wrap: true + }; + if (options && options instanceof Object) { + util.object.extend(opts, options); + } + + if (isString(object)) { + // a string with a filename + if (typeof (require) !== 'undefined') { + // load the file using require + var _module = require(object); + math_import(_module); + } + else { + throw new Error('Cannot load file: require not available.'); + } + } + else if (isSupportedType(object)) { + // a single function + name = object.name; + if (name) { + if (opts.override || math[name] === undefined) { + _import(name, object, opts); + } + } + else { + throw new Error('Cannot import an unnamed function or object'); + } + } + else if (object instanceof Object) { + // a map with functions + for (name in object) { + if (object.hasOwnProperty(name)) { + var value = object[name]; + if (isSupportedType(value)) { + _import(name, value, opts); + } + else { + math_import(value); + } + } + } + } }; - if (options && options instanceof Object) { - util.extend(opts, options); + + /** + * Add a property to the math namespace and create a chain proxy for it. + * @param {String} name + * @param {*} value + * @param {Object} options See import for a description of the options + * @private + */ + function _import(name, value, options) { + if (options.override || math[name] === undefined) { + // add to math namespace + if (options.wrap && typeof value === 'function') { + // create a wrapper around the function + math[name] = function () { + var args = []; + for (var i = 0, len = arguments.length; i < len; i++) { + args[i] = arguments[i].valueOf(); + } + return value.apply(math, args); + }; + } + else { + // just create a link to the function or value + math[name] = value; + } + + // create a proxy for the Selector + Selector.createProxy(name, value); + } } - if (isString(object)) { - // a string with a filename - if (typeof (require) !== 'undefined') { - // load the file using require - var _module = require(object); - math['import'](_module); - } - else { - throw new Error('Cannot load file: require not available.'); - } - } - else if (isSupportedType(object)) { - // a single function - name = object.name; - if (name) { - if (opts.override || math[name] === undefined) { - _import(name, object, opts); - } - } - else { - throw new Error('Cannot import an unnamed function or object'); - } - } - else if (object instanceof Object) { - // a map with functions - for (name in object) { - if (object.hasOwnProperty(name)) { - var value = object[name]; - if (isSupportedType(value)) { - _import(name, value, opts); - } - else { - math['import'](value); - } - } - } + /** + * Check whether given object is a supported type + * @param object + * @return {Boolean} + * @private + */ + function isSupportedType(object) { + return (typeof object == 'function') || + isNumber(object) || isString(object) || + isComplex(object) || isUnit(object); + // TODO: add boolean? } }; - -/** - * Add a property to the math namespace and create a chain proxy for it. - * @param {String} name - * @param {*} value - * @param {Object} options See import for a description of the options - * @private - */ -function _import(name, value, options) { - if (options.override || math[name] === undefined) { - // add to math namespace - if (options.wrap && typeof value === 'function') { - // create a wrapper around the function - math[name] = function () { - var args = []; - for (var i = 0, len = arguments.length; i < len; i++) { - args[i] = arguments[i].valueOf(); - } - return value.apply(math, args); - }; - } - else { - // just create a link to the function or value - math[name] = value; - } - - // create a proxy for the Selector - createSelectorProxy(name, value); - } - -} - -/** - * Check whether given object is a supported type - * @param object - * @return {Boolean} - * @private - */ -function isSupportedType(object) { - return (typeof object == 'function') || - isNumber(object) || isString(object) || - (object instanceof Complex) || (object instanceof Unit); - // TODO: add boolean? -} diff --git a/src/function/utils/parse.js b/src/function/utils/parse.js index 53458b06a..32a861903 100644 --- a/src/function/utils/parse.js +++ b/src/function/utils/parse.js @@ -1,4 +1,29 @@ -(function () { +module.exports = function (math) { + var util = require('../../util/index.js'), + + isString = util.string.isString, + isArray = Array.isArray, + + // types + Complex = require('./../../type/Complex.js'), + Matrix = require('./../../type/Matrix.js'), + Unit = require('./../../type/Unit.js'), + Range = require('./../../type/Range.js'), + collection = require('../../type/collection.js'), + + // scope and nodes + Scope = require('./../../expr/Scope.js'), + AssignmentNode = require('../../expr/node/AssignmentNode.js'), + BlockNode = require('../../expr/node/BlockNode.js'), + ConstantNode = require('../../expr/node/ConstantNode.js'), + FunctionNode = require('../../expr/node/FunctionNode.js'), + MatrixNode = require('../../expr/node/MatrixNode.js'), + OperatorNode = require('../../expr/node/OperatorNode.js'), + ParamsNode = require('../../expr/node/ParamsNode.js'), + SymbolNode = require('../../expr/node/SymbolNode.js'), + UpdateNode = require('../../expr/node/UpdateNode.js'), + handlers = require('../../expr/node/handlers.js'); + /** * Parse an expression. Returns a node tree, which can be evaluated by * invoking node.eval(); @@ -25,39 +50,39 @@ * nodes[2].eval(); // 12 * * @param {String | String[] | Matrix} expr - * @param {math.expr.Scope | Object} [scope] + * @param {Scope | Object} [scope] * @return {Node | Node[]} node * @throws {Error} */ - math.parse = function (expr, scope) { + math.parse = function parse (expr, scope) { if (arguments.length != 1 && arguments.length != 2) { - throw newArgumentsError('parse', arguments.length, 1, 2); + throw new util.error.ArgumentsError('parse', arguments.length, 1, 2); } // instantiate a scope var parseScope; if (scope) { - if (scope instanceof math.expr.Scope) { + if (scope instanceof Scope) { parseScope = scope; } else { - parseScope = new math.expr.Scope(scope); + parseScope = new Scope(scope); } } else { - parseScope = new math.expr.Scope(); + parseScope = new Scope(); } if (isString(expr)) { // parse a single expression expression = expr || ''; - return parse_start(parseScope); + return parseStart(parseScope); } - else if (Array.isArray(expr) || expr instanceof Matrix) { + else if (isArray(expr) || expr instanceof Matrix) { // parse an array or matrix with expressions - return util.map(expr, function (elem) { + return collection.map(expr, function (elem) { expression = elem || ''; - return parse_start(parseScope); + return parseStart(parseScope); }); } else { @@ -66,7 +91,7 @@ } }; - // token types enumeration +// token types enumeration var TOKENTYPE = { NULL : 0, DELIMITER : 1, @@ -75,7 +100,7 @@ UNKNOWN : 4 }; - // map with all delimiters +// map with all delimiters var DELIMITERS = { ',': true, '(': true, @@ -108,8 +133,6 @@ '>=': true }; - var handlers = math.expr.node.handlers; - var expression = ''; // current expression var index = 0; // current index in expr var c = ''; // current token character in expr @@ -324,11 +347,11 @@ /** * Start of the parse levels below, in order of precedence - * @param {math.expr.Scope} scope + * @param {Scope} scope * @return {Node} node * @private */ - function parse_start (scope) { + function parseStart (scope) { // get the first character in expression first(); @@ -340,7 +363,7 @@ node = new ConstantNode(undefined); } else { - node = parse_block(scope); + node = parseBlock(scope); } // check for garbage at the end of the expression @@ -364,15 +387,15 @@ * Parse a block with expressions. Expressions can be separated by a newline * character '\n', or by a semicolon ';'. In case of a semicolon, no output * of the preceding line is returned. - * @param {math.expr.Scope} scope + * @param {Scope} scope * @return {Node} node * @private */ - function parse_block (scope) { + function parseBlock (scope) { var node, block, visible; if (token != '\n' && token != ';' && token != '') { - node = parse_ans(scope); + node = parseAns(scope); } while (token == '\n' || token == ';') { @@ -387,7 +410,7 @@ getToken(); if (token != '\n' && token != ';' && token != '') { - node = parse_ans(scope); + node = parseAns(scope); visible = (token != ';'); block.add(node, visible); @@ -399,7 +422,7 @@ } if (!node) { - node = parse_ans(scope); + node = parseAns(scope); } return node; @@ -409,12 +432,12 @@ * Parse assignment of ans. * Ans is assigned when the expression itself is no variable or function * assignment - * @param {math.expr.Scope} scope + * @param {Scope} scope * @return {Node} node * @private */ - function parse_ans (scope) { - var expression = parse_function_assignment(scope); + function parseAns (scope) { + var expression = parseFunctionAssignment(scope); // create a variable definition for ans var name = 'ans'; @@ -423,11 +446,11 @@ /** * Parse a function assignment like "function f(a,b) = a*b" - * @param {math.expr.Scope} scope + * @param {Scope} scope * @return {Node} node * @private */ - function parse_function_assignment (scope) { + function parseFunctionAssignment (scope) { // TODO: keyword 'function' must become a reserved keyword // TODO: replace the 'function' keyword with an assignment operator '=>' if (token_type == TOKENTYPE.SYMBOL && token == 'function') { @@ -477,25 +500,25 @@ // parse the expression, with the correct function scope getToken(); - var expression = parse_assignment(functionScope); + var expression = parseAssignment(functionScope); return new FunctionNode(name, variables, expression, functionScope, scope); } - return parse_assignment(scope); + return parseAssignment(scope); } /** * Assignment of a variable, can be a variable like "a=2.3" or a updating an * existing variable like "matrix(2,3:5)=[6,7,8]" - * @param {math.expr.Scope} scope + * @param {Scope} scope * @return {Node} node * @private */ - function parse_assignment (scope) { + function parseAssignment (scope) { var name, params, paramScopes, expr; - var node = parse_range(scope); + var node = parseRange(scope); if (token == '=') { if (node instanceof SymbolNode) { @@ -503,7 +526,7 @@ getToken(); name = node.name; params = null; - expr = parse_assignment(scope); + expr = parseAssignment(scope); return new AssignmentNode(name, expr, scope); } else if (node instanceof ParamsNode && node.object instanceof SymbolNode) { @@ -512,7 +535,7 @@ name = node.object.name; params = node.params; paramScopes = node.paramScopes; - expr = parse_assignment(scope); + expr = parseAssignment(scope); return new UpdateNode(name, params, paramScopes, expr, scope); } else { @@ -526,11 +549,11 @@ /** * parse range, "start:end", "start:step:end", ":", "start:", ":end", etc - * @param {math.expr.Scope} scope + * @param {Scope} scope * @return {Node} node * @private */ - function parse_range (scope) { + function parseRange (scope) { var node, name, fn, params = []; if (token == ':') { @@ -539,7 +562,7 @@ } else { // explicit start - node = parse_conditions(scope); + node = parseConditions(scope); } if (token == ':') { @@ -554,7 +577,7 @@ } else { // explicit end - params.push(parse_conditions(scope)); + params.push(parseConditions(scope)); } } @@ -571,19 +594,19 @@ /** * conditions like and, or, in - * @param {math.expr.Scope} scope + * @param {Scope} scope * @return {Node} node * @private */ - function parse_conditions (scope) { + function parseConditions (scope) { var node, operators, name, fn, params; - node = parse_bitwise_conditions(scope); + node = parseBitwiseConditions(scope); // TODO: precedence of And above Or? // TODO: implement a method for unit to number conversion operators = { - 'in' : 'in' + 'in' : math['in'] /* TODO: implement conditions 'and' : 'and', '&&' : 'and', @@ -595,10 +618,10 @@ while (operators[token] !== undefined) { name = token; - fn = math[operators[name]]; + fn = operators[name]; getToken(); - params = [node, parse_bitwise_conditions(scope)]; + params = [node, parseBitwiseConditions(scope)]; node = new OperatorNode(name, fn, params); } @@ -607,27 +630,27 @@ /** * conditional operators and bitshift - * @param {math.expr.Scope} scope + * @param {Scope} scope * @return {Node} node * @private */ - function parse_bitwise_conditions (scope) { - var node = parse_comparison(scope); + function parseBitwiseConditions (scope) { + var node = parseComparison(scope); /* TODO: implement bitwise conditions var operators = { - '&' : 'bitwiseand', - '|' : 'bitwiseor', + '&' : bitwiseand, + '|' : bitwiseor, // todo: bitwise xor? - '<<': 'bitshiftleft', - '>>': 'bitshiftright' + '<<': bitshiftleft, + '>>': bitshiftright }; while (operators[token] !== undefined) { var name = token; - var fn = math[operators[name]]; + var fn = operators[name]; getToken(); - var params = [node, parse_comparison()]; + var params = [node, parseComparison()]; node = new OperatorNode(name, fn, params); } */ @@ -637,29 +660,29 @@ /** * comparison operators - * @param {math.expr.Scope} scope + * @param {Scope} scope * @return {Node} node * @private */ - function parse_comparison (scope) { + function parseComparison (scope) { var node, operators, name, fn, params; - node = parse_addsubtract(scope); + node = parseAddSubtract(scope); operators = { - '==': 'equal', - '!=': 'unequal', - '<': 'smaller', - '>': 'larger', - '<=': 'smallereq', - '>=': 'largereq' + '==': math.equal, + '!=': math.unequal, + '<': math.smaller, + '>': math.larger, + '<=': math.smallereq, + '>=': math.largereq }; while (operators[token] !== undefined) { name = token; - fn = math[operators[name]]; + fn = operators[name]; getToken(); - params = [node, parse_addsubtract(scope)]; + params = [node, parseAddSubtract(scope)]; node = new OperatorNode(name, fn, params); } @@ -668,25 +691,25 @@ /** * add or subtract - * @param {math.expr.Scope} scope + * @param {Scope} scope * @return {Node} node * @private */ - function parse_addsubtract (scope) { + function parseAddSubtract (scope) { var node, operators, name, fn, params; - node = parse_multiplydivide(scope); + node = parseMultiplyDivide(scope); operators = { - '+': 'add', - '-': 'subtract' + '+': math.add, + '-': math.subtract }; while (operators[token] !== undefined) { name = token; - fn = math[operators[name]]; + fn = operators[name]; getToken(); - params = [node, parse_multiplydivide(scope)]; + params = [node, parseMultiplyDivide(scope)]; node = new OperatorNode(name, fn, params); } @@ -695,30 +718,30 @@ /** * multiply, divide, modulus - * @param {math.expr.Scope} scope + * @param {Scope} scope * @return {Node} node * @private */ - function parse_multiplydivide (scope) { + function parseMultiplyDivide (scope) { var node, operators, name, fn, params; - node = parse_unary(scope); + node = parseUnary(scope); operators = { - '*': 'multiply', - '.*': 'emultiply', - '/': 'divide', - './': 'edivide', - '%': 'mod', - 'mod': 'mod' + '*': math.multiply, + '.*': math.emultiply, + '/': math.divide, + './': math.edivide, + '%': math.mod, + 'mod': math.mod }; while (operators[token] !== undefined) { name = token; - fn = math[operators[name]]; + fn = operators[name]; getToken(); - params = [node, parse_unary(scope)]; + params = [node, parseUnary(scope)]; node = new OperatorNode(name, fn, params); } @@ -727,37 +750,37 @@ /** * Unary minus - * @param {math.expr.Scope} scope + * @param {Scope} scope * @return {Node} node * @private */ - function parse_unary (scope) { + function parseUnary (scope) { var name, fn, params; if (token == '-') { name = token; fn = math.unary; getToken(); - params = [parse_unary(scope)]; + params = [parseUnary(scope)]; return new OperatorNode(name, fn, params); } - return parse_pow(scope); + return parsePow(scope); } /** * power * Node: power operator is right associative - * @param {math.expr.Scope} scope + * @param {Scope} scope * @return {Node} node * @private */ - function parse_pow (scope) { + function parsePow (scope) { var node, leftNode, nodes, ops, name, fn, params; nodes = [ - parse_factorial(scope) + parseFactorial(scope) ]; ops = []; @@ -765,7 +788,7 @@ while (token == '^' || token == '.^') { ops.push(token); getToken(); - nodes.push(parse_factorial(scope)); + nodes.push(parseFactorial(scope)); } // evaluate the operands from right to left (right associative) @@ -783,14 +806,14 @@ /** * Factorial - * @param {math.expr.Scope} scope + * @param {Scope} scope * @return {Node} node * @private */ - function parse_factorial (scope) { + function parseFactorial (scope) { var node, name, fn, params; - node = parse_transpose(scope); + node = parseTranspose(scope); while (token == '!') { name = token; @@ -806,14 +829,14 @@ /** * Transpose - * @param {math.expr.Scope} scope + * @param {Scope} scope * @return {Node} node * @private */ - function parse_transpose (scope) { + function parseTranspose (scope) { var node, name, fn, params; - node = parse_node_handler(scope); + node = parseNodeHandler(scope); while (token == '\'') { name = token; @@ -847,11 +870,11 @@ * * node = math.parse('plot(sin(x), x)'); * - * @param {math.expr.Scope} scope + * @param {Scope} scope * @return {Node} node * @private */ - function parse_node_handler (scope) { + function parseNodeHandler (scope) { var params, paramScopes, paramScope, @@ -872,7 +895,7 @@ if (token != ')') { paramScope = scope.createSubScope(); paramScopes.push(paramScope); - params.push(parse_range(paramScope)); + params.push(parseRange(paramScope)); // parse a list with parameters while (token == ',') { @@ -880,7 +903,7 @@ paramScope = scope.createSubScope(); paramScopes.push(paramScope); - params.push(parse_range(paramScope)); + params.push(parseRange(paramScope)); } } @@ -895,16 +918,16 @@ return new handler(params, paramScopes); } - return parse_symbol(scope); + return parseSymbol(scope); } /** * parse symbols: functions, variables, constants, units - * @param {math.expr.Scope} scope + * @param {Scope} scope * @return {Node} node * @private */ - function parse_symbol (scope) { + function parseSymbol (scope) { var node, name; if (token_type == TOKENTYPE.SYMBOL) { @@ -916,22 +939,22 @@ node = new SymbolNode(name, scope); // parse parameters - return parse_params(scope, node); + return parseParams(scope, node); } - return parse_string(scope); + return parseString(scope); } /** * parse parameters, enclosed in parenthesis - * @param {math.expr.Scope} scope + * @param {Scope} scope * @param {Node} node Node on which to apply the parameters. If there * are no parameters in the expression, the node * itself is returned * @return {Node} node * @private */ - function parse_params (scope, node) { + function parseParams (scope, node) { var params, paramScopes, paramScope; @@ -945,7 +968,7 @@ if (token != ')') { paramScope = scope.createSubScope(); paramScopes.push(paramScope); - params.push(parse_range(paramScope)); + params.push(parseRange(paramScope)); // parse a list with parameters while (token == ',') { @@ -953,7 +976,7 @@ paramScope = scope.createSubScope(); paramScopes.push(paramScope); - params.push(parse_range(paramScope)); + params.push(parseRange(paramScope)); } } @@ -971,11 +994,11 @@ /** * parse a string. * A string is enclosed by double quotes - * @param {math.expr.Scope} scope + * @param {Scope} scope * @return {Node} node * @private */ - function parse_string (scope) { + function parseString (scope) { var node, str, tPrev; if (token == '"') { @@ -998,21 +1021,21 @@ node = new ConstantNode(str); // parse parameters - node = parse_params(scope, node); + node = parseParams(scope, node); return node; } - return parse_matrix(scope); + return parseMatrix(scope); } /** * parse the matrix - * @param {math.expr.Scope} scope + * @param {Scope} scope * @return {Node} A MatrixNode * @private */ - function parse_matrix (scope) { + function parseMatrix (scope) { var array, params, r, c, rows, cols; if (token == '[') { @@ -1031,7 +1054,7 @@ r = 0; c = 0; - params[0] = [parse_assignment(scope)]; + params[0] = [parseAssignment(scope)]; // the columns in the matrix are separated by commas, and the rows by dot-comma's while (token == ',' || token == ';') { @@ -1050,7 +1073,7 @@ getToken(); } - params[r][c] = parse_assignment(scope); + params[r][c] = parseAssignment(scope); // skip newlines while (token == '\n') { @@ -1084,7 +1107,7 @@ //TODO: math.eval('[1 -2 3]') is evaluated as '[(1-2) 3]' instead of '[(1) (-2) (3)]' //TODO: '[(1) (-2) (3)]' doesn't work - params[r][c] = parse_assignment(scope); + params[r][c] = parseAssignment(scope); // skip newlines while (token == '\n') { @@ -1118,21 +1141,21 @@ } // parse parameters - array = parse_params(scope, array); + array = parseParams(scope, array); return array; } - return parse_number(scope); + return parseNumber(scope); } /** * parse a number - * @param {math.expr.Scope} scope + * @param {Scope} scope * @return {Node} node * @private */ - function parse_number (scope) { + function parseNumber (scope) { var node, value, number; if (token_type == TOKENTYPE.NUMBER) { @@ -1148,7 +1171,7 @@ // TODO: how to calculate a=3; 2/2a ? is this (2/2)*a or 2/(2*a) ? // check for implicit multiplication if (token_type == TOKENTYPE.VARIABLE) { - node = multiply(node, parse_pow()); + node = multiply(node, parsePow()); } //*/ @@ -1172,28 +1195,28 @@ node = new ConstantNode(number); // parse parameters - node = parse_params(scope, node); + node = parseParams(scope, node); return node; } - return parse_parentheses(scope); + return parseParentheses(scope); } /** * parentheses - * @param {math.expr.Scope} scope + * @param {Scope} scope * @return {Node} node * @private */ - function parse_parentheses (scope) { + function parseParentheses (scope) { var node; // check if it is a parenthesized expression if (token == '(') { // parentheses (...) getToken(); - node = parse_assignment(scope); // start again + node = parseAssignment(scope); // start again if (token != ')') { throw createSyntaxError('Parenthesis ) expected'); @@ -1204,26 +1227,26 @@ // TODO: how to calculate a=3; 2/2a ? is this (2/2)*a or 2/(2*a) ? // check for implicit multiplication if (token_type == TOKENTYPE.VARIABLE) { - node = multiply(node, parse_pow()); + node = multiply(node, parsePow()); } //*/ // parse parameters - node = parse_params(scope, node); + node = parseParams(scope, node); return node; } - return parse_end(scope); + return parseEnd(scope); } /** * Evaluated when the expression is not yet ended but expected to end - * @param {math.expr.Scope} scope + * @param {Scope} scope * @return {Node} res * @private */ - function parse_end (scope) { + function parseEnd (scope) { if (token == '') { // syntax error or unexpected end of expression throw createSyntaxError('Unexpected end of expression'); @@ -1300,5 +1323,4 @@ function createError (message) { return new Error(createErrorMessage(message)); } - -})(); +}; diff --git a/src/function/utils/select.js b/src/function/utils/select.js index dfa9e0c19..b7c1cf0c9 100644 --- a/src/function/utils/select.js +++ b/src/function/utils/select.js @@ -1,37 +1,42 @@ -/** - * Wrap any value in a Selector, allowing to perform chained operations on - * the value. - * - * All methods available in the math.js library can be called upon the selector, - * and then will be evaluated with the value itself as first argument. - * The selector can be closed by executing selector.done(), which will return - * the final value. - * - * Example usage: - * math.select(3) - * .add(4) - * .subtract(2) - * .done(); // 5 - * math.select( [[1, 2], [3, 4]] ) - * .set([1, 1], 8) - * .multiply(3) - * .done(); // [[24, 6], [9, 12]] - * - * The Selector has a number of special functions: - * - done() Finalize the chained operation and return the selectors value. - * - valueOf() The same as done() - * - toString() Executes math.format() onto the selectors value, returning - * a string representation of the value. - * - get(...) Get a subselection of the selectors value. Only applicable when - * the value has a method get, for example when value is a Matrix - * or Array. - * - set(...) Replace a subselection of the selectors value. Only applicable - * when the value has a method get, for example when value is a - * Matrix or Array. - * - * @param {*} value - * @return {math.type.Selector} selector - */ -math.select = function select(value) { - return new math.type.Selector(value); +module.exports = function (math) { + var Selector = require('../../expr/Selector.js'); + + /** + * Wrap any value in a Selector, allowing to perform chained operations on + * the value. + * + * All methods available in the math.js library can be called upon the selector, + * and then will be evaluated with the value itself as first argument. + * The selector can be closed by executing selector.done(), which will return + * the final value. + * + * Example usage: + * math.select(3) + * .add(4) + * .subtract(2) + * .done(); // 5 + * math.select( [[1, 2], [3, 4]] ) + * .set([1, 1], 8) + * .multiply(3) + * .done(); // [[24, 6], [9, 12]] + * + * The Selector has a number of special functions: + * - done() Finalize the chained operation and return the selectors value. + * - valueOf() The same as done() + * - toString() Executes math.format() onto the selectors value, returning + * a string representation of the value. + * - get(...) Get a subselection of the selectors value. Only applicable when + * the value has a method get, for example when value is a Matrix + * or Array. + * - set(...) Replace a subselection of the selectors value. Only applicable + * when the value has a method get, for example when value is a + * Matrix or Array. + * + * @param {*} value + * @return {Selector} selector + */ + math.select = function select(value) { + // TODO: check number of arguments + return new Selector(value); + }; }; diff --git a/src/function/utils/typeof.js b/src/function/utils/typeof.js index 95099185e..d9ca56e2e 100644 --- a/src/function/utils/typeof.js +++ b/src/function/utils/typeof.js @@ -1,64 +1,20 @@ -/** - * Determine the type of a variable - * - * typeof(x) - * - * @param {*} x - * @return {String} type Lower case type, for example "number", "string", - * "array". - */ -math['typeof'] = function math_typeof(x) { - if (arguments.length != 1) { - throw newArgumentsError('typeof', arguments.length, 1); - } +module.exports = function (math) { + var util = require('../../util/index.js'); - var type = typeof x, - name; + /** + * Determine the type of a variable + * + * typeof(x) + * + * @param {*} x + * @return {String} type Lower case type, for example "number", "string", + * "array". + */ + math['typeof'] = function _typeof (x) { + if (arguments.length != 1) { + throw new util.error.ArgumentsError('typeof', arguments.length, 1); + } - if (type == 'object') { - if (x == null) { - return 'null'; - } - if (x instanceof Boolean) { - return 'boolean'; - } - if (x instanceof Number) { - return 'number'; - } - if (x instanceof String) { - return 'string'; - } - if (Array.isArray(x)) { - return 'array'; - } - if (x instanceof Date) { - return 'date'; - } - if (x.constructor) { - // search functions / constants - for (name in math) { - if (math.hasOwnProperty(name)) { - if (x.constructor == math[name]) { - return name.toLowerCase(); - } - } - } - - // search data types - for (name in math.type) { - if (math.type.hasOwnProperty(name)) { - if (x.constructor == math.type[name]) { - return name.toLowerCase(); - } - } - } - - // try the constructors name as last resort - if (x.constructor.name) { - return x.constructor.name.toLowerCase(); - } - } - } - - return type; + return util.types.type(x); + }; }; diff --git a/src/functions.js b/src/functions.js deleted file mode 100644 index 470df865e..000000000 --- a/src/functions.js +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Helper methods for functions - */ - -/** - * Create a TypeError with message: - * 'Function does not support a parameter of type '; - * @param {String} name Function name - * @param {*} value1 - * @param {*} [value2] - * @return {TypeError | Error} error - */ -function newUnsupportedTypeError(name, value1, value2) { - var msg = undefined; - if (arguments.length == 2) { - var t = math['typeof'](value1); - msg = 'Function ' + name + '(' + t + ') not supported'; - } - else if (arguments.length > 2) { - var types = []; - for (var i = 1; i < arguments.length; i++) { - types.push(math['typeof'](arguments[i])); - } - msg = 'Function ' + name + '(' + types.join(', ') + ') not supported'; - } - else { - msg = 'Unsupported parameter in function ' + name; - } - - return new TypeError(msg); -} - -/** - * Create a syntax error with the message: - * 'Wrong number of arguments in function ( provided, - expected)' - * @param {String} name Function name - * @param {Number} count Actual argument count - * @param {Number} min Minimum required argument count - * @param {Number} [max] Maximum required argument count - */ -function newArgumentsError(name, count, min, max) { - var msg = 'Wrong number of arguments in function ' + name + - ' (' + count + ' provided, ' + - min + ((max != undefined) ? ('-' + max) : '') + ' expected)'; - return new SyntaxError(msg); -} diff --git a/src/index.js b/src/index.js new file mode 100644 index 000000000..d8f09423c --- /dev/null +++ b/src/index.js @@ -0,0 +1,116 @@ +// main namespace +var math = module.exports = require('./math.js'); + +// options +math.options = require('./options'); + +// expression +math.expr = require('./expr/index.js'); + +// types +math.type = require('./type/index.js'); + +// docs +math.docs = require('./docs/index.js'); + +// functions - arithmetic +require('./function/arithmetic/abs.js')(math); +require('./function/arithmetic/add.js')(math); +require('./function/arithmetic/add.js')(math); +require('./function/arithmetic/ceil.js')(math); +require('./function/arithmetic/cube.js')(math); +require('./function/arithmetic/divide.js')(math); +require('./function/arithmetic/edivide.js')(math); +require('./function/arithmetic/emultiply.js')(math); +require('./function/arithmetic/epow.js')(math); +require('./function/arithmetic/equal.js')(math); +require('./function/arithmetic/exp.js')(math); +require('./function/arithmetic/fix.js')(math); +require('./function/arithmetic/floor.js')(math); +require('./function/arithmetic/gcd.js')(math); +require('./function/arithmetic/larger.js')(math); +require('./function/arithmetic/largereq.js')(math); +require('./function/arithmetic/lcm.js')(math); +require('./function/arithmetic/log.js')(math); +require('./function/arithmetic/log10.js')(math); +require('./function/arithmetic/mod.js')(math); +require('./function/arithmetic/multiply.js')(math); +require('./function/arithmetic/pow.js')(math); +require('./function/arithmetic/round.js')(math); +require('./function/arithmetic/sign.js')(math); +require('./function/arithmetic/smaller.js')(math); +require('./function/arithmetic/smallereq.js')(math); +require('./function/arithmetic/sqrt.js')(math); +require('./function/arithmetic/square.js')(math); +require('./function/arithmetic/subtract.js')(math); +require('./function/arithmetic/unary.js')(math); +require('./function/arithmetic/unequal.js')(math); +require('./function/arithmetic/xgcd.js')(math); + +// functions - complex +require('./function/complex/arg.js')(math); +require('./function/complex/conj.js')(math); +require('./function/complex/re.js')(math); +require('./function/complex/im.js')(math); + +// functions - construction +require('./function/construction/boolean.js')(math); +require('./function/construction/complex.js')(math); +require('./function/construction/matrix.js')(math); +require('./function/construction/number.js')(math); +require('./function/construction/parser.js')(math); +require('./function/construction/range.js')(math); +require('./function/construction/string.js')(math); +require('./function/construction/unit.js')(math); + +// functions - matrix +require('./function/matrix/concat.js')(math); +require('./function/matrix/det.js')(math); +require('./function/matrix/diag.js')(math); +require('./function/matrix/eye.js')(math); +require('./function/matrix/inv.js')(math); +require('./function/matrix/ones.js')(math); +require('./function/matrix/size.js')(math); +require('./function/matrix/squeeze.js')(math); +require('./function/matrix/subset.js')(math); +require('./function/matrix/transpose.js')(math); +require('./function/matrix/zeros.js')(math); + +// functions - probability +require('./function/probability/factorial.js')(math); +require('./function/probability/random.js')(math); + +// functions - statistics +require('./function/statistics/min.js')(math); +require('./function/statistics/max.js')(math); + +// functions - trigonometry +require('./function/trigonometry/acos.js')(math); +require('./function/trigonometry/asin.js')(math); +require('./function/trigonometry/atan.js')(math); +require('./function/trigonometry/atan2.js')(math); +require('./function/trigonometry/cos.js')(math); +require('./function/trigonometry/cot.js')(math); +require('./function/trigonometry/csc.js')(math); +require('./function/trigonometry/sec.js')(math); +require('./function/trigonometry/sin.js')(math); +require('./function/trigonometry/tan.js')(math); + +// functions - units +require('./function/units/in.js')(math); + +// functions - utils +require('./function/utils/clone.js')(math); +require('./function/utils/eval.js')(math); +require('./function/utils/format.js')(math); +require('./function/utils/help.js')(math); +require('./function/utils/import.js')(math); +require('./function/utils/parse.js')(math); +require('./function/utils/select.js')(math); +require('./function/utils/typeof.js')(math); + +// constants +require('./constants.js')(math); + +// initialize Selector +require('./expr/Selector.js').init(); diff --git a/src/init.js b/src/init.js deleted file mode 100644 index 9532d2bf7..000000000 --- a/src/init.js +++ /dev/null @@ -1,10 +0,0 @@ -/** - * math.js library initialization - */ - -// initialise the Chain prototype with all functions and constants in math -for (var prop in math) { - if (math.hasOwnProperty(prop) && prop) { - createSelectorProxy(prop, math[prop]); - } -} diff --git a/src/math.js b/src/math.js new file mode 100644 index 000000000..c10ca264f --- /dev/null +++ b/src/math.js @@ -0,0 +1,2 @@ +// math.js namespace +// all constants and functions will be attached to this namespace diff --git a/src/namespace.js b/src/namespace.js deleted file mode 100644 index bd1dce379..000000000 --- a/src/namespace.js +++ /dev/null @@ -1,18 +0,0 @@ -// TODO: put "use strict"; here (but right now webstorms inspector starts -// complaining on this issue: http://youtrack.jetbrains.com/issue/WEB-7485) - -/** - * Define namespace - */ -var math = { - type: {}, - expr: { - node: { - handlers: {} - } - }, - docs: {}, - options: { - precision: 5 // number of digits in formatted output - } -}; diff --git a/src/options.js b/src/options.js new file mode 100644 index 000000000..957acc966 --- /dev/null +++ b/src/options.js @@ -0,0 +1,2 @@ +// math.js options +exports.precision = 5; // number of digits in formatted output diff --git a/src/type/Complex.js b/src/type/Complex.js index 88d86fa17..28fb03047 100644 --- a/src/type/Complex.js +++ b/src/type/Complex.js @@ -1,3 +1,9 @@ +var util = require('../util/index.js'), + + number = util.number, + isNumber = util.number.isNumber, + isString = util.string.isString; + /** * @constructor Complex * @@ -47,256 +53,251 @@ function Complex(re, im) { } } -math.type.Complex = Complex; - -// Complex parser methods in a closure -(function () { - var text, index, c; - - function skipWhitespace() { - while (c == ' ' || c == '\t') { - next(); - } - } - - function isDigitDot (c) { - return ((c >= '0' && c <= '9') || c == '.'); - } - - function isDigit (c) { - return ((c >= '0' && c <= '9')); - } - - function next() { - index++; - c = text.charAt(index); - } - - function revert(oldIndex) { - index = oldIndex; - c = text.charAt(index); - } - - function parseNumber () { - var number = ''; - var oldIndex; - oldIndex = index; - - if (c == '+') { - next(); - } - else if (c == '-') { - number += c; - next(); - } - - if (!isDigitDot(c)) { - // a + or - must be followed by a digit - revert(oldIndex); - return null; - } - - // get number, can have a single dot - if (c == '.') { - number += c; - next(); - if (!isDigit(c)) { - // this is no legal number, it is just a dot - revert(oldIndex); - return null; - } - } - else { - while (isDigit(c)) { - number += c; - next(); - } - if (c == '.') { - number += c; - next(); - } - } - while (isDigit(c)) { - number += c; - next(); - } - - // check for scientific notation like "2.3e-4" or "1.23e50" - if (c == 'E' || c == 'e') { - number += c; - next(); - - if (c == '+' || c == '-') { - number += c; - next(); - } - - // Scientific notation MUST be followed by an exponent - if (!isDigit(c)) { - // this is no legal number, exponent is missing. - revert(oldIndex); - return null; - } - - while (isDigit(c)) { - number += c; - next(); - } - } - - return number; - } - - function parseComplex () { - // check for 'i', '-i', '+i' - var cnext = text.charAt(index + 1); - if (c == 'I' || c == 'i') { - next(); - return '1'; - } - else if ((c == '+' || c == '-') && (cnext == 'I' || cnext == 'i')) { - var number = (c == '+') ? '1' : '-1'; - next(); - next(); - return number; - } - - return null; - } - - /** - * Create a complex number from a provided real and imaginary number. - * When the imaginary part is zero, a real number is returned instead of - * a complex number. For example: - * Complex.create(2, 3); // returns a Complex(2, 3) - * Complex.create(2, 0); // returns a Number 2 - * - * @param {Number} re - * @param {Number} im - * @return {Complex | Number} value - */ - Complex.create = function (re, im) { - if (im == 0) { - return re; - } - else { - return new Complex(re, im); - } - }; - - /** - * Parse a complex number from a string. For example Complex.parse("2 + 3i") - * will return a Complex value where re = 2, im = 3. - * Returns null if provided string does not contain a valid complex number. - * @param {String} str - * @returns {Complex | null} complex - */ - Complex.parse = function parse(str) { - text = str; - index = -1; - c = ''; - - if (!isString(text)) { - return null; - } - - next(); - skipWhitespace(); - var first = parseNumber(); - if (first) { - if (c == 'I' || c == 'i') { - // pure imaginary number - next(); - skipWhitespace(); - if (c) { - // garbage at the end. not good. - return null; - } - - return new Complex(0, Number(first)); - } - else { - // complex and real part - skipWhitespace(); - var separator = c; - if (separator != '+' && separator != '-') { - // pure real number - skipWhitespace(); - if (c) { - // garbage at the end. not good. - return null; - } - - return new Complex(Number(first), 0); - } - else { - // complex and real part - next(); - skipWhitespace(); - var second = parseNumber(); - if (second) { - if (c != 'I' && c != 'i') { - // 'i' missing at the end of the complex number - return null; - } - next(); - } - else { - second = parseComplex(); - if (!second) { - // imaginary number missing after separator - return null; - } - } - - if (separator == '-') { - if (second[0] == '-') { - second = '+' + second.substring(1); - } - else { - second = '-' + second; - } - } - - next(); - skipWhitespace(); - if (c) { - // garbage at the end. not good. - return null; - } - - return new Complex(Number(first), Number(second)); - } - } - } - else { - // check for 'i', '-i', '+i' - first = parseComplex(); - if (first) { - skipWhitespace(); - if (c) { - // garbage at the end. not good. - return null; - } - - return new Complex(0, Number(first)); - } - } - - return null; - }; - -})(); - /** * Test whether value is a Complex value * @param {*} value * @return {Boolean} isComplex */ -function isComplex(value) { +Complex.isComplex = function isComplex(value) { return (value instanceof Complex); +}; + +// private variables and functions for the parser +var text, index, c; + +function skipWhitespace() { + while (c == ' ' || c == '\t') { + next(); + } } +function isDigitDot (c) { + return ((c >= '0' && c <= '9') || c == '.'); +} + +function isDigit (c) { + return ((c >= '0' && c <= '9')); +} + +function next() { + index++; + c = text.charAt(index); +} + +function revert(oldIndex) { + index = oldIndex; + c = text.charAt(index); +} + +function parseNumber () { + var number = ''; + var oldIndex; + oldIndex = index; + + if (c == '+') { + next(); + } + else if (c == '-') { + number += c; + next(); + } + + if (!isDigitDot(c)) { + // a + or - must be followed by a digit + revert(oldIndex); + return null; + } + + // get number, can have a single dot + if (c == '.') { + number += c; + next(); + if (!isDigit(c)) { + // this is no legal number, it is just a dot + revert(oldIndex); + return null; + } + } + else { + while (isDigit(c)) { + number += c; + next(); + } + if (c == '.') { + number += c; + next(); + } + } + while (isDigit(c)) { + number += c; + next(); + } + + // check for scientific notation like "2.3e-4" or "1.23e50" + if (c == 'E' || c == 'e') { + number += c; + next(); + + if (c == '+' || c == '-') { + number += c; + next(); + } + + // Scientific notation MUST be followed by an exponent + if (!isDigit(c)) { + // this is no legal number, exponent is missing. + revert(oldIndex); + return null; + } + + while (isDigit(c)) { + number += c; + next(); + } + } + + return number; +} + +function parseComplex () { + // check for 'i', '-i', '+i' + var cnext = text.charAt(index + 1); + if (c == 'I' || c == 'i') { + next(); + return '1'; + } + else if ((c == '+' || c == '-') && (cnext == 'I' || cnext == 'i')) { + var number = (c == '+') ? '1' : '-1'; + next(); + next(); + return number; + } + + return null; +} + +/** + * Create a complex number from a provided real and imaginary number. + * When the imaginary part is zero, a real number is returned instead of + * a complex number. For example: + * Complex.create(2, 3); // returns a Complex(2, 3) + * Complex.create(2, 0); // returns a Number 2 + * + * @param {Number} re + * @param {Number} im + * @return {Complex | Number} value + */ +Complex.create = function create (re, im) { + if (im == 0) { + return re; + } + else { + return new Complex(re, im); + } +}; + +/** + * Parse a complex number from a string. For example Complex.parse("2 + 3i") + * will return a Complex value where re = 2, im = 3. + * Returns null if provided string does not contain a valid complex number. + * @param {String} str + * @returns {Complex | null} complex + */ +Complex.parse = function parse(str) { + text = str; + index = -1; + c = ''; + + if (!isString(text)) { + return null; + } + + next(); + skipWhitespace(); + var first = parseNumber(); + if (first) { + if (c == 'I' || c == 'i') { + // pure imaginary number + next(); + skipWhitespace(); + if (c) { + // garbage at the end. not good. + return null; + } + + return new Complex(0, Number(first)); + } + else { + // complex and real part + skipWhitespace(); + var separator = c; + if (separator != '+' && separator != '-') { + // pure real number + skipWhitespace(); + if (c) { + // garbage at the end. not good. + return null; + } + + return new Complex(Number(first), 0); + } + else { + // complex and real part + next(); + skipWhitespace(); + var second = parseNumber(); + if (second) { + if (c != 'I' && c != 'i') { + // 'i' missing at the end of the complex number + return null; + } + next(); + } + else { + second = parseComplex(); + if (!second) { + // imaginary number missing after separator + return null; + } + } + + if (separator == '-') { + if (second[0] == '-') { + second = '+' + second.substring(1); + } + else { + second = '-' + second; + } + } + + next(); + skipWhitespace(); + if (c) { + // garbage at the end. not good. + return null; + } + + return new Complex(Number(first), Number(second)); + } + } + } + else { + // check for 'i', '-i', '+i' + first = parseComplex(); + if (first) { + skipWhitespace(); + if (c) { + // garbage at the end. not good. + return null; + } + + return new Complex(0, Number(first)); + } + } + + return null; +}; + /** * Create a copy of the complex value * @return {Complex} clone @@ -311,8 +312,8 @@ Complex.prototype.clone = function () { */ Complex.prototype.toString = function () { var str = ''; - var strRe = util.formatNumber(this.re, math.options.precision); - var strIm = util.formatNumber(this.im, math.options.precision); + var strRe = number.format(this.re); + var strIm = number.format(this.im); if (this.im == 0) { // real value @@ -346,10 +347,21 @@ Complex.prototype.toString = function () { } else { str = strRe + ' - ' + - util.formatNumber(Math.abs(this.im), math.options.precision) + 'i'; + number.format(Math.abs(this.im)) + 'i'; } } } return str; }; + + +// exports +module.exports = Complex; + +// to trick my IDE which doesn't get it +exports.isComplex = Complex.isComplex; +exports.parse = Complex.parse; +exports.create = Complex.create; + +util.types.addType('complex', Complex); diff --git a/src/type/Help.js b/src/type/Help.js index b91cb5bcb..55d8fad91 100644 --- a/src/type/Help.js +++ b/src/type/Help.js @@ -1,3 +1,8 @@ +var math = require('../math.js'), + util = require('../util/index.js'), + + object = util.object, + string = util.string; /** * Documentation object @@ -11,11 +16,18 @@ */ function Help (doc) { if (doc) { - util.extend(this, doc); + object.extend(this, doc); } } -math.type.Help = Help; +/** + * Test whether a value is an instance of Help + * @param {*} value + * @return {Boolean} isHelp + */ +Help.isHelp = function isHelp (value) { + return (value instanceof Help); +}; /** * Generate readable description from a Help object @@ -48,7 +60,7 @@ Help.prototype.toString = function () { } desc += ' ' + expr + '\n'; if (res && !(res instanceof Help)) { - desc += ' ' + math.format(res) + '\n'; + desc += ' ' + string.format(res) + '\n'; } } desc += '\n'; @@ -57,7 +69,6 @@ Help.prototype.toString = function () { desc += 'See also: ' + this.seealso.join(', ') + '\n'; } - return desc; }; @@ -67,5 +78,13 @@ Help.prototype.toString = function () { * Export the help object to JSON */ Help.prototype.toJSON = function () { - return util.extend({}, this); + return object.extend({}, this); }; + +// exports +module.exports = Help; + +// to trick my IDE which doesn't get it +exports.isHelp = Help.isHelp; + +util.types.addType('help', Help); diff --git a/src/type/Matrix.js b/src/type/Matrix.js index 2f60485d5..78b1a38bd 100644 --- a/src/type/Matrix.js +++ b/src/type/Matrix.js @@ -1,3 +1,11 @@ +var util = require('../util/index.js'), + Range = require('./Range.js'), + + number = util.number, + string = util.string, + array = util.array, + object = util.object; + /** * @constructor Matrix * @@ -35,7 +43,7 @@ function Matrix(data) { } else if (data != null) { // unsupported type - throw new TypeError('Unsupported type of data (' + math['typeof'](data) + ')'); + throw new TypeError('Unsupported type of data (' + object.type(data) + ')'); } else { // nothing provided @@ -43,10 +51,17 @@ function Matrix(data) { } // verify the size of the array - this._size = util.size(this._data); + this._size = array.size(this._data); } -math.type.Matrix = Matrix; +/** + * Test whether an object is a Matrix + * @param {*} object + * @return {Boolean} isMatrix + */ +Matrix.isMatrix = function (object) { + return (object instanceof Matrix); +}; /** * Get a value or a submatrix of the matrix. @@ -63,7 +78,7 @@ Matrix.prototype.get = function (index) { } else if (Array.isArray(index)) { isScalar = !index.some(function (elem) { - var size = math.size(elem); + var size = array.size(elem.valueOf()); return (size.length != 0) && (size != [0]); }); } @@ -99,14 +114,14 @@ Matrix.prototype.get = function (index) { * Get a single value from an array. The method tests whether: * - index is a non-negative integer * - index does not exceed the dimensions of array - * @param {Array} array + * @param {Array} arr * @param {Number} index Zero-based index * @return {*} value * @private */ -function _get (array, index) { - util.validateIndex(index, array.length); - return array[index]; // zero-based index +function _get (arr, index) { + array.validateIndex(index, arr.length); + return arr[index]; // zero-based index } /** @@ -122,7 +137,7 @@ function _getScalar (data, index) { index.forEach(function (i) { data = _get(data, i); }); - return math.clone(data); + return object.clone(data); } /** @@ -244,7 +259,7 @@ Matrix.prototype.set = function (index, submatrix) { } else if (Array.isArray(index)) { isScalar = !index.some(function (elem) { - var size = math.size(elem); + var size = array.size(elem.valueOf()); return (size.length != 0) && (size != [0]); }); } @@ -264,7 +279,7 @@ Matrix.prototype.set = function (index, submatrix) { if (isScalar) { // set a scalar // check whether submatrix is no matrix/array - if (math.size(submatrix).valueOf().length != 0) { + if (array.size(submatrix.valueOf()).length != 0) { throw new TypeError('Scalar value expected'); } @@ -276,11 +291,11 @@ Matrix.prototype.set = function (index, submatrix) { } else { // set a submatrix - var size = this._size.concat(); - _setSubmatrix (this._data, size, index, 0, submatrix); - if (!util.deepEqual(this._size, size)) { + var subsize = this._size.concat(); + _setSubmatrix (this._data, subsize, index, 0, submatrix); + if (!object.deepEqual(this._size, subsize)) { _init(this._data); - this.resize(size); + this.resize(subsize); } } @@ -290,17 +305,17 @@ Matrix.prototype.set = function (index, submatrix) { /** * Replace a single value in an array. The method tests whether index is a * non-negative integer - * @param {Array} array + * @param {Array} arr * @param {Number} index Zero-based index * @param {*} value * @private */ -function _set (array, index, value) { - util.validateIndex(index); +function _set (arr, index, value) { + array.validateIndex(index); if (Array.isArray(value)) { throw new TypeError('Dimension mismatch, value expected instead of array'); } - array[index] = value; // zero-based index + arr[index] = value; // zero-based index } /** @@ -320,7 +335,7 @@ function _setScalar (data, size, index, value) { for (var i = 0; i < index.length; i++) { var index_i = index[i]; - util.validateIndex(index_i); + array.validateIndex(index_i); if ((size[i] == null) || (index_i + 1 > size[i])) { size[i] = index_i + 1; // size is index + 1 as index is zero-based resized = true; @@ -328,7 +343,7 @@ function _setScalar (data, size, index, value) { } if (resized) { - util.resize(data, size, 0); + array.resize(data, size, 0); } var len = size.length; @@ -352,9 +367,9 @@ function _setScalar (data, size, index, value) { */ function _setScalar1D (data, size, index, value) { var row = index[0]; - util.validateIndex(row); + array.validateIndex(row); if (row + 1 > size[0]) { - util.resize(data, [row + 1], 0); // size is index + 1 as index is zero-based + array.resize(data, [row + 1], 0); // size is index + 1 as index is zero-based size[0] = row + 1; } data[row] = value; // zero-based index @@ -371,8 +386,8 @@ function _setScalar1D (data, size, index, value) { function _setScalar2D (data, size, index, value) { var row = index[0]; var col = index[1]; - util.validateIndex(row); - util.validateIndex(col); + array.validateIndex(row); + array.validateIndex(col); var resized = false; if (row + 1 > (size[0] || 0)) { @@ -384,7 +399,7 @@ function _setScalar2D (data, size, index, value) { resized = true; } if (resized) { - util.resize(data, size, 0); + array.resize(data, size, 0); } data[row][col] = value; // zero-based index @@ -461,8 +476,8 @@ function _init(array) { * with zeros. */ Matrix.prototype.resize = function (size, defaultValue) { - util.resize(this._data, size, defaultValue); - this._size = math.clone(size); + array.resize(this._data, size, defaultValue); + this._size = object.clone(size); }; /** @@ -471,8 +486,8 @@ Matrix.prototype.resize = function (size, defaultValue) { */ Matrix.prototype.clone = function () { var matrix = new Matrix(); - matrix._data = math.clone(this._data); - matrix._size = math.clone(this._size); + matrix._data = object.clone(this._data); + matrix._size = object.clone(this._size); return matrix; }; @@ -509,7 +524,7 @@ Matrix.prototype.map = function (callback) { } }; matrix._data = recurse(this._data, 0); - matrix._size = math.clone(this._size); + matrix._size = object.clone(this._size); return matrix; }; @@ -552,7 +567,7 @@ Matrix.prototype.toScalar = function () { return null; } else { - return math.clone(scalar); + return object.clone(scalar); } }; @@ -637,7 +652,7 @@ Matrix.prototype.isVector = function () { * @returns {Array} array */ Matrix.prototype.toArray = function () { - return math.clone(this._data); + return object.clone(this._data); }; /** @@ -653,5 +668,13 @@ Matrix.prototype.valueOf = function () { * @returns {String} str */ Matrix.prototype.toString = function () { - return math.format(this._data); + return string.format(this._data); }; + +// exports +module.exports = Matrix; + +// to trick my IDE which doesn't get it +exports.isMatrix = Matrix.isMatrix; + +util.types.addType('matrix', Matrix); diff --git a/src/type/Number.js b/src/type/Number.js deleted file mode 100644 index 238c44f81..000000000 --- a/src/type/Number.js +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Utility functions for Numbers - */ - - -/** - * Test whether value is a Number - * @param {*} value - * @return {Boolean} isNumber - */ -function isNumber(value) { - return (value instanceof Number) || (typeof value == 'number'); -} - -/** - * Check if a number is integer - * @param {Number} value - * @return {Boolean} isInteger - */ -function isInteger(value) { - return (value == Math.round(value)); -} diff --git a/src/type/Range.js b/src/type/Range.js index d37b59f37..85fe270d7 100644 --- a/src/type/Range.js +++ b/src/type/Range.js @@ -1,3 +1,9 @@ +var util = require('../util/index.js'), + + number = util.number, + string = util.string, + array = util.array; + /** * @constructor Range * Create a range. A range works similar to an Array, with functions like @@ -33,13 +39,13 @@ function Range(start, step, end) { 'Range constructor must be called with the new operator'); } - if (start != null && !isNumber(start)) { + if (start != null && !number.isNumber(start)) { throw new TypeError('Parameter start must be a number'); } - if (end != null && !isNumber(end)) { + if (end != null && !number.isNumber(end)) { throw new TypeError('Parameter end must be a number'); } - if (step != null && !isNumber(step)) { + if (step != null && !number.isNumber(step)) { throw new TypeError('Parameter step must be a number'); } @@ -48,8 +54,6 @@ function Range(start, step, end) { this.step = (step != null) ? step : 1; } -math.type.Range = Range; - /** * Parse a string into a range, * The string contains the start, optional step, and end, separated by a colon. @@ -58,8 +62,8 @@ math.type.Range = Range; * @param {String} str * @return {Range | null} range */ -Range.parse = function (str) { - if (!isString(str)) { +Range.parse = function parse (str) { + if (!string.isString(str)) { return null; } @@ -90,6 +94,15 @@ Range.prototype.clone = function () { return new Range(this.start, this.step, this.end); }; +/** + * Test whether an object is a Range + * @param {*} object + * @return {Boolean} isRange + */ +Range.isRange = function isRange(object) { + return (object instanceof Range); +}; + /** * Retrieve the size of the range. * @returns {Number[]} size @@ -101,7 +114,7 @@ Range.prototype.size = function () { end = Number(this.end), diff = end - start; - if (math.sign(step) == math.sign(diff)) { + if (number.sign(step) == number.sign(diff)) { len = Math.floor((diff) / step) + 1; } else if (diff == 0) { @@ -158,14 +171,6 @@ Range.prototype.map = function (callback) { return array; }; -/** - * Create a Matrix with a copy of the Ranges data - * @return {Matrix} matrix - */ -Range.prototype.toMatrix = function () { - return new Matrix(this.toArray()); -}; - /** * Create an Array with a copy of the Ranges data * @returns {Array} array @@ -180,8 +185,7 @@ Range.prototype.toArray = function () { /** * Create an array with a copy of the Ranges data. - * This method is equal to Range.toArray, and is available for compatibility - * with Matrix. + * This method is equal to Range.toArray. * @return {Array} vector */ Range.prototype.toVector = Range.prototype.toArray; @@ -231,10 +235,20 @@ Range.prototype.valueOf = function () { * @returns {String} str */ Range.prototype.toString = function () { - var str = math.format(Number(this.start)); + var str = number.format(Number(this.start)); if (this.step != 1) { - str += ':' + math.format(Number(this.step)); + str += ':' + number.format(Number(this.step)); } - str += ':' + math.format(Number(this.end)); + str += ':' + number.format(Number(this.end)); return str; }; + + +// exports +module.exports = Range; + +// to trick my IDE which doesn't get it +exports.isRange = Range.isRange; +exports.parse = Range.parse; + +util.types.addType('range', Range); diff --git a/src/type/String.js b/src/type/String.js deleted file mode 100644 index d5ab82c34..000000000 --- a/src/type/String.js +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Utility functions for Strings - */ - -/** - * Test whether value is a String - * @param {*} value - * @return {Boolean} isString - */ -function isString(value) { - return (value instanceof String) || (typeof value == 'string'); -} diff --git a/src/type/Unit.js b/src/type/Unit.js index 105abb63b..5e4b9b6f2 100644 --- a/src/type/Unit.js +++ b/src/type/Unit.js @@ -1,3 +1,10 @@ +var util = require('../util/index.js'), + + number = util.number, + string = util.string, + isNumber = util.number.isNumber, + isString = util.string.isString; + /** * @constructor Unit * @@ -36,8 +43,8 @@ function Unit(value, unit) { this.prefix = res.prefix; } else { - this.unit = Unit.UNIT_NONE; - this.prefix = Unit.PREFIX_NONE; // link to a list with supported prefixes + this.unit = UNIT_NONE; + this.prefix = PREFIX_NONE; // link to a list with supported prefixes } if (value != null) { @@ -50,176 +57,172 @@ function Unit(value, unit) { } } -math.type.Unit = Unit; +// private variables and functions for the Unit parser +var text, index, c; -(function() { - var text, index, c; +function skipWhitespace() { + while (c == ' ' || c == '\t') { + next(); + } +} - function skipWhitespace() { - while (c == ' ' || c == '\t') { - next(); - } +function isDigitDot (c) { + return ((c >= '0' && c <= '9') || c == '.'); +} + +function isDigit (c) { + return ((c >= '0' && c <= '9')); +} + +function next() { + index++; + c = text.charAt(index); +} + +function revert(oldIndex) { + index = oldIndex; + c = text.charAt(index); +} + +function parseNumber () { + var number = ''; + var oldIndex; + oldIndex = index; + + if (c == '+') { + next(); + } + else if (c == '-') { + number += c; + next(); } - function isDigitDot (c) { - return ((c >= '0' && c <= '9') || c == '.'); + if (!isDigitDot(c)) { + // a + or - must be followed by a digit + revert(oldIndex); + return null; } - function isDigit (c) { - return ((c >= '0' && c <= '9')); - } - - function next() { - index++; - c = text.charAt(index); - } - - function revert(oldIndex) { - index = oldIndex; - c = text.charAt(index); - } - - function parseNumber () { - var number = ''; - var oldIndex; - oldIndex = index; - - if (c == '+') { - next(); - } - else if (c == '-') { - number += c; - next(); - } - - if (!isDigitDot(c)) { - // a + or - must be followed by a digit + // get number, can have a single dot + if (c == '.') { + number += c; + next(); + if (!isDigit(c)) { + // this is no legal number, it is just a dot revert(oldIndex); return null; } - - // get number, can have a single dot - if (c == '.') { - number += c; - next(); - if (!isDigit(c)) { - // this is no legal number, it is just a dot - revert(oldIndex); - return null; - } - } - else { - while (isDigit(c)) { - number += c; - next(); - } - if (c == '.') { - number += c; - next(); - } - } + } + else { while (isDigit(c)) { number += c; next(); } - - // check for scientific notation like "2.3e-4" or "1.23e50" - if (c == 'E' || c == 'e') { + if (c == '.') { number += c; next(); - - if (c == '+' || c == '-') { - number += c; - next(); - } - - // Scientific notation MUST be followed by an exponent - if (!isDigit(c)) { - // this is no legal number, exponent is missing. - revert(oldIndex); - return null; - } - - while (isDigit(c)) { - number += c; - next(); - } } - - return number; + } + while (isDigit(c)) { + number += c; + next(); } - function parseUnit() { - var unit = ''; + // check for scientific notation like "2.3e-4" or "1.23e50" + if (c == 'E' || c == 'e') { + number += c; + next(); - skipWhitespace(); - while (c && c != ' ' && c != '\t') { - unit += c; + if (c == '+' || c == '-') { + number += c; next(); } - return unit || null; - } - - /** - * Parse a string into a unit. Returns null if the provided string does not - * contain a valid unit. - * @param {String} str A string like "5.2 inch", "4e2 kg" - * @return {Unit | null} unit - */ - Unit.parse = function parse(str) { - text = str; - index = -1; - c = ''; - - if (!isString(text)) { + // Scientific notation MUST be followed by an exponent + if (!isDigit(c)) { + // this is no legal number, exponent is missing. + revert(oldIndex); return null; } + while (isDigit(c)) { + number += c; + next(); + } + } + + return number; +} + +function parseUnit() { + var unit = ''; + + skipWhitespace(); + while (c && c != ' ' && c != '\t') { + unit += c; + next(); + } + + return unit || null; +} + +/** + * Parse a string into a unit. Returns null if the provided string does not + * contain a valid unit. + * @param {String} str A string like "5.2 inch", "4e2 kg" + * @return {Unit | null} unit + */ +Unit.parse = function parse(str) { + text = str; + index = -1; + c = ''; + + if (!isString(text)) { + return null; + } + + next(); + skipWhitespace(); + var value = parseNumber(); + var unit; + if (value) { + unit = parseUnit(); + next(); skipWhitespace(); - var value = parseNumber(); - var unit; - if (value) { - unit = parseUnit(); - - next(); - skipWhitespace(); - if (c) { - // garbage at the end. not good. - return null; - } - - if (value && unit) { - return new Unit(Number(value), unit); - } - } - else { - unit = parseUnit(); - - next(); - skipWhitespace(); - if (c) { - // garbage at the end. not good. - return null; - } - - return new Unit(null, unit) + if (c) { + // garbage at the end. not good. + return null; } - return null; - }; + if (value && unit) { + return new Unit(Number(value), unit); + } + } + else { + unit = parseUnit(); -})(); + next(); + skipWhitespace(); + if (c) { + // garbage at the end. not good. + return null; + } + + return new Unit(null, unit) + } + + return null; +}; /** * Test whether value is of type Unit * @param {*} value * @return {Boolean} isUnit */ -function isUnit(value) { +Unit.isUnit = function isUnit(value) { return (value instanceof Unit); -} +}; /** * create a copy of this unit @@ -274,11 +277,10 @@ Unit.prototype._unnormalize = function (value, prefixValue) { * @private */ function _findUnit(str) { - var UNITS = Unit.UNITS; for (var i = 0, iMax = UNITS.length; i < iMax; i++) { var UNIT = UNITS[i]; - if (util.endsWith(str, UNIT.name) ) { + if (string.endsWith(str, UNIT.name) ) { var prefixLen = (str.length - UNIT.name.length); var prefixName = str.substring(0, prefixLen); var prefix = UNIT.prefixes[prefixName]; @@ -307,7 +309,7 @@ Unit.isPlainUnit = function (unit) { /** * check if this unit has given base unit - * @param {Unit.BASE_UNITS} base + * @param {BASE_UNITS | undefined} base */ Unit.prototype.hasBase = function(base) { if (this.unit.base === undefined) { @@ -392,12 +394,12 @@ Unit.prototype.toString = function() { if (!this.fixPrefix) { var bestPrefix = this._bestPrefix(); value = this._unnormalize(this.value, bestPrefix.value); - str = (this.value != null) ? util.formatNumber(value, math.options.precision) + ' ' : ''; + str = (this.value != null) ? number.format(value) + ' ' : ''; str += bestPrefix.name + this.unit.name; } else { value = this._unnormalize(this.value); - str = (this.value != null) ? util.formatNumber(value, math.options.precision) + ' ' : ''; + str = (this.value != null) ? number.format(value) + ' ' : ''; str += this.prefix.name + this.unit.name; } return str; @@ -414,7 +416,7 @@ Unit.prototype._bestPrefix = function () { // though with a little offset of 1.2 for nicer values: you get a // sequence 1mm 100mm 500mm 0.6m 1m 10m 100m 500m 0.6km 1km ... var absValue = Math.abs(this.value / this.unit.value); - var bestPrefix = Unit.PREFIX_NONE; + var bestPrefix = PREFIX_NONE; var bestDiff = Math.abs( Math.log(absValue / bestPrefix.value) / Math.LN10 - 1.2); @@ -437,7 +439,7 @@ Unit.prototype._bestPrefix = function () { return bestPrefix; }; -Unit.PREFIXES = { +var PREFIXES = { 'NONE': { '': {'name': '', 'value': 1, 'scientific': true} }, @@ -534,9 +536,9 @@ Unit.PREFIXES = { } }; -Unit.PREFIX_NONE = {'name': '', 'value': 1, 'scientific': true}; +var PREFIX_NONE = {'name': '', 'value': 1, 'scientific': true}; -Unit.BASE_UNITS = { +var BASE_UNITS = { 'NONE': {}, 'LENGTH': {}, // meter @@ -554,14 +556,11 @@ Unit.BASE_UNITS = { 'BIT': {} // bit (digital) }; -var BASE_UNITS = Unit.BASE_UNITS; -var PREFIXES = Unit.PREFIXES; +BASE_UNIT_NONE = {}; -Unit.BASE_UNIT_NONE = {}; +UNIT_NONE = {'name': '', 'base': BASE_UNIT_NONE, 'value': 1, 'offset': 0}; -Unit.UNIT_NONE = {'name': '', 'base': Unit.BASE_UNIT_NONE, 'value': 1, 'offset': 0}; - -Unit.UNITS = [ +var UNITS = [ // length {'name': 'meter', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.LONG, 'value': 1, 'offset': 0}, {'name': 'inch', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.0254, 'offset': 0}, @@ -709,3 +708,18 @@ Unit.UNITS = [ {'name': 'B', 'base': BASE_UNITS.BIT, 'prefixes': PREFIXES.BINARY_SHORT, 'value': 8, 'offset': 0}, {'name': 'bytes', 'base': BASE_UNITS.BIT, 'prefixes': PREFIXES.BINARY_LONG, 'value': 8, 'offset': 0} ]; + +Unit.PREFIXES = PREFIXES; +Unit.BASE_UNITS = BASE_UNITS; +Unit.UNITS = UNITS; + + +// exports +module.exports = Unit; + +// to trick my IDE which doesn't get it +exports.isUnit = Unit.isUnit; +exports.isPlainUnit = Unit.isPlainUnit; +exports.parse = Unit.parse; + +util.types.addType('unit', Unit); diff --git a/src/type/collection.js b/src/type/collection.js new file mode 100644 index 000000000..9cbb3d6f4 --- /dev/null +++ b/src/type/collection.js @@ -0,0 +1,225 @@ +var util = require('../util/index.js'), + + Matrix = require('./Matrix.js'), + Range = require('./Range.js'), + + isArray = Array.isArray, + isString = util.string.isString; + +// utility methods for strings, objects, and arrays + +/** + * Convert function arguments to an array. Arguments can have the following + * signature: + * fn() + * fn(n) + * fn(m, n, p, ...) + * fn([m, n, p, ...]) + * @param {...Number | Array | Matrix} args + * @returns {Array} array + */ +exports.argsToArray = function argsToArray(args) { + var array; + if (args.length == 0) { + // fn() + array = []; + } + else if (args.length == 1) { + // fn(n) + // fn([m, n, p, ...]) + array = args[0]; + if (array instanceof Matrix) { + array = array.toVector(); + } + if (array instanceof Range) { + array = array.valueOf(); + } + if (!isArray(array)) { + array = [array]; + } + } + else { + // fn(m, n, p, ...) + array = []; + for (var i = 0; i < args.length; i++) { + array[i] = args[i]; + } + } + return array; +}; + + +/** + * Test whether a value is a collection: an Array, Matrix, or Range + * @param {*} x + * @returns {boolean} isCollection + */ +exports.isCollection = function isCollection (x) { + return (isArray(x) || (x instanceof Matrix) || (x instanceof Range)); +}; + +// TODO: write the map, deepMap, map2, and deepMap2 functions in a more concise way + +/** + * Execute function fn element wise for each element in array. + * Returns an array with the results + * @param {Array | Matrix | Range} array + * @param {function} fn + * @return {Array | Matrix} res + */ +exports.map = function map(array, fn) { + if (array && array.map) { + return array.map(function (x) { + return fn(x); + }); + } + else { + throw new TypeError('Array expected'); + } +}; + +/** + * Execute function fn element wise for each element in array and any nested + * array + * Returns an array with the results + * @param {Array | Matrix | Range} array + * @param {function} fn + * @return {Array | Matrix} res + */ +exports.deepMap = function deepMap(array, fn) { + if (array && array.map) { + return array.map(function (x) { + return deepMap(x, fn); + }); + } + else { + return fn(array); + } +}; + +/** + * Execute function fn element wise for each entry in two given arrays, or + * for a (scalar) object and array pair. Returns an array with the results + * @param {Array | Matrix | Range | Object} array1 + * @param {Array | Matrix | Range | Object} array2 + * @param {function} fn + * @return {Array | Matrix} res + */ +exports.map2 = function map2(array1, array2, fn) { + var res, len, i; + + // handle Matrix + if (array1 instanceof Matrix || array2 instanceof Matrix) { + return new Matrix(map2(array1.valueOf(), array2.valueOf(), fn)); + } + + // handle Range + if (array1 instanceof Range || array2 instanceof Range) { + // TODO: exports.map2 does not utilize Range.map + return map2(array1.valueOf(), array2.valueOf(), fn); + } + + if (isArray(array1)) { + if (isArray(array2)) { + // fn(array, array) + if (array1.length != array2.length) { + throw new RangeError('Dimension mismatch ' + + '(' + array1.length + ' != ' + array2.length + ')'); + } + + res = []; + len = array1.length; + for (i = 0; i < len; i++) { + res[i] = fn(array1[i], array2[i]); + } + } + else { + // fn(array, object) + res = []; + len = array1.length; + for (i = 0; i < len; i++) { + res[i] = fn(array1[i], array2); + } + } + } + else { + if (isArray(array2)) { + // fn(object, array) + res = []; + len = array2.length; + for (i = 0; i < len; i++) { + res[i] = fn(array1, array2[i]); + } + } + else { + // fn(object, object) + res = fn(array1, array2); + } + } + + return res; +}; + +/** + * Execute function fn element wise for each entry in two given arrays, + * and for any nested array. Objects can also be scalar objects. + * Returns an array with the results. + * @param {Array | Matrix | Range | Object} array1 + * @param {Array | Matrix | Range | Object} array2 + * @param {function} fn + * @return {Array | Matrix} res + */ +exports.deepMap2 = function deepMap2(array1, array2, fn) { + var res, len, i; + + // handle Matrix + if (array1 instanceof Matrix || array2 instanceof Matrix) { + return new Matrix(deepMap2(array1.valueOf(), array2.valueOf(), fn)); + } + + // handle Range + if (array1 instanceof Range || array2 instanceof Range) { + // TODO: util.deepMap2 does not utilize Range.map + return deepMap2(array1.valueOf(), array2.valueOf(), fn); + } + + if (isArray(array1)) { + if (isArray(array2)) { + // fn(array, array) + if (array1.length != array2.length) { + throw new RangeError('Dimension mismatch ' + + '(' + array1.length + ' != ' + array2.length + ')'); + } + + res = []; + len = array1.length; + for (i = 0; i < len; i++) { + res[i] = deepMap2(array1[i], array2[i], fn); + } + } + else { + // fn(array, object) + res = []; + len = array1.length; + for (i = 0; i < len; i++) { + res[i] = deepMap2(array1[i], array2, fn); + } + } + } + else { + if (isArray(array2)) { + // fn(object, array) + res = []; + len = array2.length; + for (i = 0; i < len; i++) { + res[i] = deepMap2(array1, array2[i], fn); + } + } + else { + // fn(object, object) + res = fn(array1, array2); + } + } + + return res; +}; diff --git a/src/type/index.js b/src/type/index.js new file mode 100644 index 000000000..1b1021889 --- /dev/null +++ b/src/type/index.js @@ -0,0 +1,7 @@ +exports.Complex = require('./Complex.js'); +exports.Range = require('./Range.js'); +exports.Matrix = require('./Matrix.js'); +exports.Unit = require('./Unit.js'); +exports.Help = require('./Help.js'); + +exports.collection = require('./collection.js'); diff --git a/src/util.js b/src/util.js deleted file mode 100644 index 2ac058c82..000000000 --- a/src/util.js +++ /dev/null @@ -1,711 +0,0 @@ -// utility methods for strings, objects, and arrays -var util = (function () { - var util = {}; - - /** - * Convert a number to a formatted string representation. - * @param {Number} value The value to be formatted - * @param {Number} [precision] number of digits in formatted output - * @return {String} formattedValue The formatted value - */ - util.formatNumber = function formatNumber(value, precision) { - if (value === Infinity) { - return 'Infinity'; - } - else if (value === -Infinity) { - return '-Infinity'; - } - else if (isNaN(value)) { - return 'NaN'; - } - - // TODO: what is a nice limit for non-scientific values? - var abs = Math.abs(value); - if ( (abs > 0.001 && abs < 100000) || abs == 0.0 ) { - // round the value to a limited number of precision - return util.toPrecision(value, precision); - } - else { - // scientific notation - var exp = Math.round(Math.log(abs) / Math.LN10); - var v = value / (Math.pow(10.0, exp)); - return util.toPrecision(v, precision) + 'e' + exp; - } - }; - - /** - * Round a value to a maximum number of precision. Trailing zeros will be - * removed. - * @param {Number} value - * @param {Number} [precision] Number of digits in formatted output - * @returns {string} str - */ - util.toPrecision = function toPrecision (value, precision) { - return value.toPrecision(precision).replace(_trailingZeros, function (a, b, c) { - return a.substring(0, a.length - (b.length ? 0 : 1) - c.length); - }); - }; - - /** @private */ - var _trailingZeros = /\.(\d*?)(0+)$/g; - - /** - * Recursively format an n-dimensional matrix - * Example output: "[[1, 2], [3, 4]]" - * @param {Array} array - * @returns {String} str - */ - util.formatArray = function formatArray (array) { - if (Array.isArray(array)) { - var str = '['; - var len = array.length; - for (var i = 0; i < len; i++) { - if (i != 0) { - str += ', '; - } - str += util.formatArray(array[i]); - } - str += ']'; - return str; - } - else { - return math.format(array); - } - }; - - /** - * Recursively format an n-dimensional array, output looks like - * "[1, 2, 3]" - * @param {Array} array - * @returns {string} str - */ - util.formatArray2d = function formatArray2d (array) { - var str = '['; - var s = util.size(array); - - if (s.length != 2) { - throw new RangeError('Array must be two dimensional (size: ' + - util.formatArray(s) + ')'); - } - - var rows = s[0]; - var cols = s[1]; - for (var r = 0; r < rows; r++) { - if (r != 0) { - str += '; '; - } - - var row = array[r]; - for (var c = 0; c < cols; c++) { - if (c != 0) { - str += ', '; - } - var cell = row[c]; - if (cell != undefined) { - str += math.format(cell); - } - } - } - str += ']'; - - return str; - }; - - /** - * Convert function arguments to an array. Arguments can have the following - * signature: - * fn() - * fn(n) - * fn(m, n, p, ...) - * fn([m, n, p, ...]) - * @param {...Number | Array | Matrix} args - * @returns {Array} array - */ - util.argsToArray = function argsToArray(args) { - var array; - if (args.length == 0) { - // fn() - array = []; - } - else if (args.length == 1) { - // fn(n) - // fn([m, n, p, ...]) - array = args[0]; - if (array instanceof Matrix) { - array = array.toVector(); - } - if (array instanceof Range) { - array = array.valueOf(); - } - if (!Array.isArray(array)) { - array = [array]; - } - } - else { - // fn(m, n, p, ...) - array = []; - for (var i = 0; i < args.length; i++) { - array[i] = args[i]; - } - } - return array; - }; - - /** - * Check if a text ends with a certain string. - * @param {String} text - * @param {String} search - */ - util.endsWith = function endsWith(text, search) { - var start = text.length - search.length; - var end = text.length; - return (text.substring(start, end) === search); - }; - - /** - * Extend object a with the properties of object b - * @param {Object} a - * @param {Object} b - * @return {Object} a - */ - util.extend = function extend (a, b) { - for (var prop in b) { - if (b.hasOwnProperty(prop)) { - a[prop] = b[prop]; - } - } - return a; - }; - - /** - * Deep extend an object a with the properties of object b - * @param {Object} a - * @param {Object} b - * @returns {Object} - */ - util.deepExtend = function deepExtend (a, b) { - for (var prop in b) { - if (b.hasOwnProperty(prop)) { - if (b[prop] && b[prop].constructor === Object) { - if (a[prop] === undefined) { - a[prop] = {}; - } - if (a[prop].constructor === Object) { - deepExtend(a[prop], b[prop]); - } - else { - a[prop] = b[prop]; - } - } else { - a[prop] = b[prop]; - } - } - } - return a; - }; - - /** - * Create a semi UUID - * b: http://stackoverflow.com/a/105074/1262753 - * @return {String} uuid - */ - util.randomUUID = function randomUUID() { - var S4 = function () { - return Math.floor( - Math.random() * 0x10000 /* 65536 */ - ).toString(16); - }; - - return ( - S4() + S4() + '-' + - S4() + '-' + - S4() + '-' + - S4() + '-' + - S4() + S4() + S4() - ); - }; - - // TODO: write the map, deepMap, map2, and deepMap2 functions in a more concise way - - /** - * Execute function fn element wise for each element in array. - * Returns an array with the results - * @param {Array | Matrix | Range} array - * @param {function} fn - * @return {Array | Matrix} res - */ - util.map = function map(array, fn) { - if (Array.isArray(array) || array instanceof Matrix || array instanceof Range) { - return array.map(function (x) { - return fn(x); - }); - } - else { - throw new TypeError('Array expected'); - } - }; - - /** - * Execute function fn element wise for each element in array and any nested - * array - * Returns an array with the results - * @param {Array | Matrix | Range} array - * @param {function} fn - * @return {Array | Matrix} res - */ - util.deepMap = function map(array, fn) { - if (Array.isArray(array) || array instanceof Matrix || array instanceof Range) { - return array.map(function (x) { - return map(x, fn); - }); - } - else { - return fn(array); - } - }; - - /** - * Execute function fn element wise for each entry in two given arrays, or - * for a (scalar) object and array pair. Returns an array with the results - * @param {Array | Matrix | Range | Object} array1 - * @param {Array | Matrix | Range | Object} array2 - * @param {function} fn - * @return {Array | Matrix} res - */ - util.map2 = function map2(array1, array2, fn) { - var res, len, i; - - // handle Matrix - if (array1 instanceof Matrix || array2 instanceof Matrix) { - return new Matrix(util.map2(array1.valueOf(), array2.valueOf(), fn)); - } - - // handle Range - if (array1 instanceof Range || array2 instanceof Range) { - // TODO: util.map2 does not utilize Range.map - return util.map2(array1.valueOf(), array2.valueOf(), fn); - } - - if (Array.isArray(array1)) { - if (Array.isArray(array2)) { - // fn(array, array) - if (array1.length != array2.length) { - throw new RangeError('Dimension mismatch ' + - '(' + array1.length + ' != ' + array2.length + ')'); - } - - res = []; - len = array1.length; - for (i = 0; i < len; i++) { - res[i] = fn(array1[i], array2[i]); - } - } - else { - // fn(array, object) - res = []; - len = array1.length; - for (i = 0; i < len; i++) { - res[i] = fn(array1[i], array2); - } - } - } - else { - if (Array.isArray(array2)) { - // fn(object, array) - res = []; - len = array2.length; - for (i = 0; i < len; i++) { - res[i] = fn(array1, array2[i]); - } - } - else { - // fn(object, object) - res = fn(array1, array2); - } - } - - return res; - }; - - /** - * Execute function fn element wise for each entry in two given arrays, - * and for any nested array. Objects can also be scalar objects. - * Returns an array with the results. - * @param {Array | Matrix | Range | Object} array1 - * @param {Array | Matrix | Range | Object} array2 - * @param {function} fn - * @return {Array | Matrix} res - */ - util.deepMap2 = function map2(array1, array2, fn) { - var res, len, i; - - // handle Matrix - if (array1 instanceof Matrix || array2 instanceof Matrix) { - return new Matrix(map2(array1.valueOf(), array2.valueOf(), fn)); - } - - // handle Range - if (array1 instanceof Range || array2 instanceof Range) { - // TODO: util.deepMap2 does not utilize Range.map - return map2(array1.valueOf(), array2.valueOf(), fn); - } - - if (Array.isArray(array1)) { - if (Array.isArray(array2)) { - // fn(array, array) - if (array1.length != array2.length) { - throw new RangeError('Dimension mismatch ' + - '(' + array1.length + ' != ' + array2.length + ')'); - } - - res = []; - len = array1.length; - for (i = 0; i < len; i++) { - res[i] = map2(array1[i], array2[i], fn); - } - } - else { - // fn(array, object) - res = []; - len = array1.length; - for (i = 0; i < len; i++) { - res[i] = map2(array1[i], array2, fn); - } - } - } - else { - if (Array.isArray(array2)) { - // fn(object, array) - res = []; - len = array2.length; - for (i = 0; i < len; i++) { - res[i] = map2(array1, array2[i], fn); - } - } - else { - // fn(object, object) - res = fn(array1, array2); - } - } - - return res; - }; - - /** - * Creates a new object with the results of calling a provided function on - * every prop in the object. - * @param {Object} object The object. - * @param {function} callback Mapping function - * @return {Object | Array} mappedObject - */ - util.mapObject = function mapObject (object, callback) { - var m = {}; - for (var key in object) { - if (object.hasOwnProperty(key)) { - m[key] = callback(object[key]); - } - } - return m; - }; - - /** - * Deep test equality of all fields in two pairs of arrays or objects. - * @param {Array | Object} a - * @param {Array | Object} b - * @returns {boolean} - */ - util.deepEqual = function deepEqual (a, b) { - var prop, i, len; - if (Array.isArray(a)) { - if (!Array.isArray(b)) { - return false; - } - - for (i = 0, len = a.length; i < len; i++) { - if (!util.deepEqual(a[i], b[i])) { - return false; - } - } - return true; - } - else if (a instanceof Object) { - if (Array.isArray(b) || !(b instanceof Object)) { - return false; - } - - for (prop in a) { - if (a.hasOwnProperty(prop)) { - if (!util.deepEqual(a[prop], b[prop])) { - return false; - } - } - } - for (prop in b) { - if (b.hasOwnProperty(prop)) { - if (!util.deepEqual(a[prop], b[prop])) { - return false; - } - } - } - return true; - } - else { - return (a.valueOf() == b.valueOf()); - } - }; - - /** - * Recursively calculate the size of a multi dimensional array. - * @param {Array} x - * @Return {Number[]} size - * @throws RangeError - */ - function _size(x) { - if (Array.isArray(x)) { - var sizeX = x.length; - if (sizeX) { - var size0 = _size(x[0]); - if (size0[0] == 0) { - return [0].concat(size0); - } - else { - return [sizeX].concat(size0); - } - } - else { - return [sizeX]; - } - } - else { - return []; - } - } - - /** - * Calculate the size of a multi dimensional array. - * All elements in the array are checked for matching dimensions using the - * method validate - * @param {Array} x - * @Return {Number[]} size - * @throws RangeError - */ - util.size = function size (x) { - // calculate the size - var s = _size(x); - - // verify the size - util.validate(x, s); - - return s; - }; - - /** - * Recursively validate whether each element in a multi dimensional array - * has a size corresponding to the provided size array. - * @param {Array} array Array to be validated - * @param {Number[]} size Array with the size of each dimension - * @param {Number} dim Current dimension - * @throws RangeError - */ - function _validate(array, size, dim) { - var i; - var len = array.length; - - if (len != size[dim]) { - throw new RangeError('Dimension mismatch (' + len + ' != ' + size[dim] + ')'); - } - - if (dim < size.length - 1) { - // recursively validate each child array - var dimNext = dim + 1; - for (i = 0; i < len; i++) { - var child = array[i]; - if (!Array.isArray(child)) { - throw new RangeError('Dimension mismatch ' + - '(' + (size.length - 1) + ' < ' + size.length + ')'); - } - _validate(array[i], size, dimNext); - } - } - else { - // last dimension. none of the childs may be an array - for (i = 0; i < len; i++) { - if (Array.isArray(array[i])) { - throw new RangeError('Dimension mismatch ' + - '(' + (size.length + 1) + ' > ' + size.length + ')'); - } - } - } - } - - /** - * Recursively validate whether each array in a multi dimensional array - * is empty (zero size) and has the correct number dimensions. - * @param {Array} array Array to be validated - * @param {Number[]} size Array with the size of each dimension - * @param {Number} dim Current dimension - * @throws RangeError - */ - function _validateEmpty(array, size, dim) { - if (dim < size.length - 1) { - var child = array[0]; - if (array.length != 1 || !Array.isArray(child)) { - throw new RangeError('Dimension mismatch ' + '(' + array.length + ' > 0)'); - } - - _validateEmpty(child, size, dim + 1); - } - else { - // last dimension. test if empty - if (array.length) { - throw new RangeError('Dimension mismatch ' + '(' + array.length + ' > 0)'); - } - } - } - - /** - * Validate whether each element in a multi dimensional array has - * a size corresponding to the provided size array. - * @param {Array} array Array to be validated - * @param {Number[]} size Array with the size of each dimension - * @throws RangeError - */ - util.validate = function validate(array, size) { - var isScalar = (size.length == 0); - if (isScalar) { - // scalar - if (Array.isArray(array)) { - throw new RangeError('Dimension mismatch (' + array.length + ' != 0)'); - } - return; - } - - var hasZeros = (size.indexOf(0) != -1); - if (hasZeros) { - // array where all dimensions are zero - size.forEach(function (value) { - if (value != 0) { - throw new RangeError('Invalid size, all dimensions must be ' + - 'either zero or non-zero (size: ' + util.formatArray(size) + ')'); - } - }); - - _validateEmpty(array, size, 0); - } - else { - _validate(array, size, 0); - } - }; - - /** - * Test whether index is an integer number with index >= 0 and index < length - * @param {*} index Zero-based index - * @param {Number} [length] Length of the array - */ - util.validateIndex = function validateIndex (index, length) { - if (!isNumber(index) || !isInteger(index)) { - throw new TypeError('Index must be an integer (value: ' + index + ')'); - } - if (index < 0) { - throw new RangeError('Index out of range (' + index + ' < 0)'); - } - if (length !== undefined && index >= length) { - throw new RangeError('Index out of range (' + index + ' >= ' + length + ')'); - } - }; - - /** - * Recursively resize a multi dimensional array - * @param {Array} array Array to be resized - * @param {Number[]} size Array with the size of each dimension - * @param {Number} dim Current dimension - * @param {*} [defaultValue] Value to be filled in in new entries, - * 0 by default. - * @private - */ - function _resize (array, size, dim, defaultValue) { - if (!Array.isArray(array)) { - throw new TypeError('Array expected'); - } - - var len = array.length, - newLen = size[dim]; - - if (len != newLen) { - if(newLen > array.length) { - // enlarge - for (var i = array.length; i < newLen; i++) { - array[i] = defaultValue ? math.clone(defaultValue) : 0; - } - } - else { - // shrink - array.length = size[dim]; - } - len = array.length; - } - - if (dim < size.length - 1) { - // recursively validate each child array - var dimNext = dim + 1; - for (i = 0; i < len; i++) { - child = array[i]; - if (!Array.isArray(child)) { - child = [child]; - array[i] = child; - } - _resize(child, size, dimNext, defaultValue); - } - } - else { - // last dimension - for (i = 0; i < len; i++) { - var child = array[i]; - while (Array.isArray(child)) { - child = child[0]; - } - array[i] = child; - } - } - } - - /** - * Resize a multi dimensional array - * @param {Array} array Array to be resized - * @param {Number[]} size Array with the size of each dimension - * @param {*} [defaultValue] Value to be filled in in new entries, - * 0 by default - */ - util.resize = function resize(array, size, defaultValue) { - // TODO: what to do with scalars, when size=[] ? - - // check the type of size - if (!Array.isArray(size)) { - throw new TypeError('Size must be an array (size is ' + math['typeof'](size) + ')'); - } - - // check whether size contains positive integers - size.forEach(function (value) { - if (!isNumber(value) || !isInteger(value) || value < 0) { - throw new TypeError('Invalid size, must contain positive integers ' + - '(size: ' + util.formatArray(size) + ')'); - } - }); - - var hasZeros = (size.indexOf(0) != -1); - if (hasZeros) { - // array where all dimensions are zero - size.forEach(function (value) { - if (value != 0) { - throw new RangeError('Invalid size, all dimensions must be ' + - 'either zero or non-zero (size: ' + util.formatArray(size) + ')'); - } - }); - } - - // recursively resize - _resize(array, size, 0, defaultValue); - }; - - return util; -})(); diff --git a/src/util/array.js b/src/util/array.js new file mode 100644 index 000000000..2c6e60711 --- /dev/null +++ b/src/util/array.js @@ -0,0 +1,266 @@ +var number = require('./number'), + string = require('./string'), + object = require('./object'); + +/** + * Recursively calculate the size of a multi dimensional array. + * @param {Array} x + * @Return {Number[]} size + * @throws RangeError + * @private + */ +function _size(x) { + if (Array.isArray(x)) { + var sizeX = x.length; + if (sizeX) { + var size0 = _size(x[0]); + if (size0[0] == 0) { + return [0].concat(size0); + } + else { + return [sizeX].concat(size0); + } + } + else { + return [sizeX]; + } + } + else { + return []; + } +} + +/** + * Calculate the size of a multi dimensional array. + * All elements in the array are checked for matching dimensions using the + * method validate + * @param {Array} x + * @Return {Number[]} size + * @throws RangeError + */ +exports.size = function size (x) { + // calculate the size + var s = _size(x); + + // verify the size + exports.validate(x, s); + + return s; +}; + +/** + * Recursively validate whether each element in a multi dimensional array + * has a size corresponding to the provided size array. + * @param {Array} array Array to be validated + * @param {Number[]} size Array with the size of each dimension + * @param {Number} dim Current dimension + * @throws RangeError + * @private + */ +function _validate(array, size, dim) { + var i; + var len = array.length; + + if (len != size[dim]) { + throw new RangeError('Dimension mismatch (' + len + ' != ' + size[dim] + ')'); + } + + if (dim < size.length - 1) { + // recursively validate each child array + var dimNext = dim + 1; + for (i = 0; i < len; i++) { + var child = array[i]; + if (!Array.isArray(child)) { + throw new RangeError('Dimension mismatch ' + + '(' + (size.length - 1) + ' < ' + size.length + ')'); + } + _validate(array[i], size, dimNext); + } + } + else { + // last dimension. none of the childs may be an array + for (i = 0; i < len; i++) { + if (Array.isArray(array[i])) { + throw new RangeError('Dimension mismatch ' + + '(' + (size.length + 1) + ' > ' + size.length + ')'); + } + } + } +} + +/** + * Recursively validate whether each array in a multi dimensional array + * is empty (zero size) and has the correct number dimensions. + * @param {Array} array Array to be validated + * @param {Number[]} size Array with the size of each dimension + * @param {Number} dim Current dimension + * @throws RangeError + * @private + */ +function _validateEmpty(array, size, dim) { + if (dim < size.length - 1) { + var child = array[0]; + if (array.length != 1 || !Array.isArray(child)) { + throw new RangeError('Dimension mismatch ' + '(' + array.length + ' > 0)'); + } + + _validateEmpty(child, size, dim + 1); + } + else { + // last dimension. test if empty + if (array.length) { + throw new RangeError('Dimension mismatch ' + '(' + array.length + ' > 0)'); + } + } +} + +/** + * Validate whether each element in a multi dimensional array has + * a size corresponding to the provided size array. + * @param {Array} array Array to be validated + * @param {Number[]} size Array with the size of each dimension + * @throws RangeError + */ +exports.validate = function validate(array, size) { + var isScalar = (size.length == 0); + if (isScalar) { + // scalar + if (Array.isArray(array)) { + throw new RangeError('Dimension mismatch (' + array.length + ' != 0)'); + } + return; + } + + var hasZeros = (size.indexOf(0) != -1); + if (hasZeros) { + // array where all dimensions are zero + size.forEach(function (value) { + if (value != 0) { + throw new RangeError('Invalid size, all dimensions must be ' + + 'either zero or non-zero (size: ' + exports.formatArray(size) + ')'); + } + }); + + _validateEmpty(array, size, 0); + } + else { + _validate(array, size, 0); + } +}; + +/** + * Test whether index is an integer number with index >= 0 and index < length + * @param {*} index Zero-based index + * @param {Number} [length] Length of the array + */ +exports.validateIndex = function validateIndex (index, length) { + if (!number.isNumber(index) || !number.isInteger(index)) { + throw new TypeError('Index must be an integer (value: ' + index + ')'); + } + if (index < 0) { + throw new RangeError('Index out of range (' + index + ' < 0)'); + } + if (length !== undefined && index >= length) { + throw new RangeError('Index out of range (' + index + ' >= ' + length + ')'); + } +}; + +/** + * Recursively resize a multi dimensional array + * @param {Array} array Array to be resized + * @param {Number[]} size Array with the size of each dimension + * @param {Number} dim Current dimension + * @param {*} [defaultValue] Value to be filled in in new entries, + * 0 by default. + * @private + */ +function _resize (array, size, dim, defaultValue) { + if (!Array.isArray(array)) { + throw new TypeError('Array expected'); + } + + var len = array.length, + newLen = size[dim]; + + if (len != newLen) { + if(newLen > array.length) { + // enlarge + for (var i = array.length; i < newLen; i++) { + array[i] = defaultValue ? object.clone(defaultValue) : 0; + } + } + else { + // shrink + array.length = size[dim]; + } + len = array.length; + } + + if (dim < size.length - 1) { + // recursively validate each child array + var dimNext = dim + 1; + for (i = 0; i < len; i++) { + child = array[i]; + if (!Array.isArray(child)) { + child = [child]; + array[i] = child; + } + _resize(child, size, dimNext, defaultValue); + } + } + else { + // last dimension + for (i = 0; i < len; i++) { + var child = array[i]; + while (Array.isArray(child)) { + child = child[0]; + } + array[i] = child; + } + } +} + +/** + * Resize a multi dimensional array + * @param {Array} array Array to be resized + * @param {Array.} size Array with the size of each dimension + * @param {*} [defaultValue] Value to be filled in in new entries, + * 0 by default + */ +exports.resize = function resize(array, size, defaultValue) { + // TODO: what to do with scalars, when size=[] ? + + // check the type of size + if (!Array.isArray(size)) { + throw new TypeError('Size must be an array (size is ' + object.type(size) + ')'); + } + + // check whether size contains positive integers + size.forEach(function (value) { + if (!number.isNumber(value) || !number.isInteger(value) || value < 0) { + throw new TypeError('Invalid size, must contain positive integers ' + + '(size: ' + string.format(size) + ')'); + } + }); + + var hasZeros = (size.indexOf(0) != -1); + if (hasZeros) { + // array where all dimensions are zero + size.forEach(function (value) { + if (value != 0) { + throw new RangeError('Invalid size, all dimensions must be ' + + 'either zero or non-zero (size: ' + string.format(size) + ')'); + } + }); + } + + // recursively resize + _resize(array, size, 0, defaultValue); +}; + +/** + * Test whether an object is an array + * @param {*} value + * @return {Boolean} isArray + */ +exports.isArray = Array.isArray; \ No newline at end of file diff --git a/src/type/Boolean.js b/src/util/boolean.js similarity index 68% rename from src/type/Boolean.js rename to src/util/boolean.js index c3bf4d610..dab950308 100644 --- a/src/type/Boolean.js +++ b/src/util/boolean.js @@ -1,13 +1,8 @@ -/** - * Utility functions for Booleans - */ - - /** * Test whether value is a Boolean * @param {*} value * @return {Boolean} isBoolean */ -function isBoolean(value) { +exports.isBoolean = function isBoolean(value) { return (value instanceof Boolean) || (typeof value == 'boolean'); -} +}; diff --git a/src/util/error.js b/src/util/error.js new file mode 100644 index 000000000..f30a3f77c --- /dev/null +++ b/src/util/error.js @@ -0,0 +1,47 @@ +var types = require('./types.js'); + +/** + * Create a TypeError with message: + * 'Function does not support a parameter of type '; + * @param {String} name Function name + * @param {*} value1 + * @param {*} [value2] + * @extends TypeError + */ +exports.UnsupportedTypeError = function UnsupportedTypeError(name, value1, value2) { + if (arguments.length == 2) { + var t = types.type(value1); + this.message = 'Function ' + name + '(' + t + ') not supported'; + } + else if (arguments.length > 2) { + var args = []; + for (var i = 1; i < arguments.length; i++) { + args.push(types.type(arguments[i])); + } + this.message = 'Function ' + name + '(' + args.join(', ') + ') not supported'; + } + else { + this.message = 'Unsupported parameter in function ' + name; + } +}; + +exports.UnsupportedTypeError.prototype = new TypeError(); +exports.UnsupportedTypeError.prototype.name = 'UnsupportedTypeError'; + +/** + * Create a syntax error with the message: + * 'Wrong number of arguments in function ( provided, - expected)' + * @param {String} name Function name + * @param {Number} count Actual argument count + * @param {Number} min Minimum required argument count + * @param {Number} [max] Maximum required argument count + * @extends SyntaxError + */ +exports.ArgumentsError = function ArgumentsError(name, count, min, max) { + this.message = 'Wrong number of arguments in function ' + name + + ' (' + count + ' provided, ' + + min + ((max != undefined) ? ('-' + max) : '') + ' expected)'; +}; + +exports.ArgumentsError.prototype = new SyntaxError(); +exports.ArgumentsError.prototype.name = 'ArgumentError'; diff --git a/src/util/index.js b/src/util/index.js new file mode 100644 index 000000000..ea420bdda --- /dev/null +++ b/src/util/index.js @@ -0,0 +1,7 @@ +exports.array = require('./array'); +exports.boolean = require('./boolean'); +exports.error = require('./error'); +exports.number = require('./number'); +exports.object = require('./object'); +exports.string = require('./string'); +exports.types = require('./types'); diff --git a/src/util/number.js b/src/util/number.js new file mode 100644 index 000000000..578aa1213 --- /dev/null +++ b/src/util/number.js @@ -0,0 +1,87 @@ +var options = require('../options.js'); + +/** + * Test whether value is a Number + * @param {*} value + * @return {Boolean} isNumber + */ +exports.isNumber = function isNumber(value) { + return (value instanceof Number) || (typeof value == 'number'); +}; + +/** + * Check if a number is integer + * @param {Number} value + * @return {Boolean} isInteger + */ +exports.isInteger = function isInteger(value) { + return (value == Math.round(value)); +}; + +/** + * Convert a number to a formatted string representation. + * @param {Number} value The value to be formatted + * @param {Number} [precision] number of digits in formatted output + * @return {String} formattedValue The formatted value + */ +exports.format = function format(value, precision) { + if (value === Infinity) { + return 'Infinity'; + } + else if (value === -Infinity) { + return '-Infinity'; + } + else if (isNaN(value)) { + return 'NaN'; + } + + // TODO: what is a nice limit for non-scientific values? + var abs = Math.abs(value); + if ( (abs > 0.001 && abs < 100000) || abs == 0.0 ) { + // round the value to a limited number of precision + return exports.toPrecision(value, precision); + } + else { + // scientific notation + var exp = Math.round(Math.log(abs) / Math.LN10); + var v = value / (Math.pow(10.0, exp)); + return exports.toPrecision(v, precision) + 'e' + exp; + } +}; + +/** + * Calculate the sign of a number + * @param {Number} x + * @returns {*} + */ +exports.sign = function sign (x) { + if (x > 0) { + return 1; + } + else if (x < 0) { + return -1; + } + else { + return 0; + } +}; + +/** + * Round a value to a maximum number of precision. Trailing zeros will be + * removed. + * @param {Number} value + * @param {Number} [precision] Number of digits in formatted output + * @returns {string} str + */ +exports.toPrecision = function toPrecision (value, precision) { + if (precision === undefined) { + precision = options.precision; + } + + return value.toPrecision(precision).replace(_trailingZeros, function (a, b, c) { + return a.substring(0, a.length - (b.length ? 0 : 1) - c.length); + }); +}; + +/** @private */ +var _trailingZeros = /\.(\d*?)(0+)$/g; diff --git a/src/util/object.js b/src/util/object.js new file mode 100644 index 000000000..c5d4b0faf --- /dev/null +++ b/src/util/object.js @@ -0,0 +1,131 @@ +var number = require('./number.js'), + string = require('./string.js'), + bool = require('./boolean.js'); + +/** + * Clone an object + * + * clone(x) + * + * @param {*} x + * @return {*} clone + */ +exports.clone = function clone(x) { + if (x == null) { + // null or undefined + return x; + } + + if (typeof(x.clone) === 'function') { + return x.clone(); + } + + if (number.isNumber(x) || string.isString(x) || bool.isBoolean(x)) { + return x; + } + + if (Array.isArray(x)) { + return x.map(function (value) { + return clone(value); + }); + } + + if (x instanceof Object) { + var m = {}; + for (var key in x) { + if (x.hasOwnProperty(key)) { + m[key] = clone(x[key]); + } + } + } + + throw new TypeError('Cannot clone ' + x); +}; + +/** + * Extend object a with the properties of object b + * @param {Object} a + * @param {Object} b + * @return {Object} a + */ +exports.extend = function extend (a, b) { + for (var prop in b) { + if (b.hasOwnProperty(prop)) { + a[prop] = b[prop]; + } + } + return a; +}; + +/** + * Deep extend an object a with the properties of object b + * @param {Object} a + * @param {Object} b + * @returns {Object} + */ +exports.deepExtend = function deepExtend (a, b) { + for (var prop in b) { + if (b.hasOwnProperty(prop)) { + if (b[prop] && b[prop].constructor === Object) { + if (a[prop] === undefined) { + a[prop] = {}; + } + if (a[prop].constructor === Object) { + deepExtend(a[prop], b[prop]); + } + else { + a[prop] = b[prop]; + } + } else { + a[prop] = b[prop]; + } + } + } + return a; +}; + +/** + * Deep test equality of all fields in two pairs of arrays or objects. + * @param {Array | Object} a + * @param {Array | Object} b + * @returns {boolean} + */ +exports.deepEqual = function deepEqual (a, b) { + var prop, i, len; + if (Array.isArray(a)) { + if (!Array.isArray(b)) { + return false; + } + + for (i = 0, len = a.length; i < len; i++) { + if (!exports.deepEqual(a[i], b[i])) { + return false; + } + } + return true; + } + else if (a instanceof Object) { + if (Array.isArray(b) || !(b instanceof Object)) { + return false; + } + + for (prop in a) { + if (a.hasOwnProperty(prop)) { + if (!exports.deepEqual(a[prop], b[prop])) { + return false; + } + } + } + for (prop in b) { + if (b.hasOwnProperty(prop)) { + if (!exports.deepEqual(a[prop], b[prop])) { + return false; + } + } + } + return true; + } + else { + return (a.valueOf() == b.valueOf()); + } +}; diff --git a/src/util/string.js b/src/util/string.js new file mode 100644 index 000000000..072e70241 --- /dev/null +++ b/src/util/string.js @@ -0,0 +1,150 @@ +var number = require('./number.js'); + +/** + * Test whether value is a String + * @param {*} value + * @return {Boolean} isString + */ +exports.isString = function isString(value) { + return (value instanceof String) || (typeof value == 'string'); +}; + +/** + * Check if a text ends with a certain string. + * @param {String} text + * @param {String} search + */ +exports.endsWith = function endsWith(text, search) { + var start = text.length - search.length; + var end = text.length; + return (text.substring(start, end) === search); +}; + +/** + * Format a value of any type into a string. Interpolate values into the string. + * Numbers are rounded off to a maximum number of 5 digits by default. + * Usage: + * math.format(value) + * math.format(template, object) + * + * Example usage: + * math.format(2/7); // '0.28571' + * math.format(new Complex(2, 3)); // '2 + 3i' + * math.format('Hello $name! The date is $date', { + * name: 'user', + * date: new Date().toISOString().substring(0, 10) + * }); // 'hello user! The date is 2013-03-23' + * + * @param {String | *} template Template or value + * @param {Object} [values] + * @return {String} str + */ +exports.format = function format(template, values) { + var num = arguments.length; + + if (num == 1) { + // just format a value as string + var value = arguments[0]; + if (number.isNumber(value)) { + return number.format(value); + } + + if (Array.isArray(value)) { + return formatArray(value); + } + + if (exports.isString(value)) { + return '"' + value + '"'; + } + + if (value instanceof Object) { + return value.toString(); + } + + return String(value); + } + else { + if (!exports.isString(template)) { + throw new TypeError('String expected as first parameter in function format'); + } + if (!(values instanceof Object)) { + throw new TypeError('Object expected as second parameter in function format'); + } + + // format values into a string + return template.replace(/\$([\w\.]+)/g, function (original, key) { + var keys = key.split('.'); + var value = values[keys.shift()]; + while (keys.length && value != undefined) { + var k = keys.shift(); + value = k ? value[k] : value + '.'; + } + return value != undefined ? value : original; + } + ); + } +}; + +/** + * Recursively format an n-dimensional matrix + * Example output: "[[1, 2], [3, 4]]" + * @param {Array} array + * @returns {String} str + */ +function formatArray (array) { + if (Array.isArray(array)) { + var str = '['; + var len = array.length; + for (var i = 0; i < len; i++) { + if (i != 0) { + str += ', '; + } + str += formatArray(array[i]); + } + str += ']'; + return str; + } + else { + return exports.format(array); + } +} + +/** + * Recursively format an n-dimensional array, output looks like + * "[1, 2, 3]" + * @param {Array} array + * @returns {string} str + */ +/* TODO: use function formatArray2d or remove it +function formatArray2d (array) { + var str = '['; + var s = size(array); + + if (s.length != 2) { + throw new RangeError('Array must be two dimensional (size: ' + + formatArray(s) + ')'); + } + + var rows = s[0]; + var cols = s[1]; + for (var r = 0; r < rows; r++) { + if (r != 0) { + str += '; '; + } + + var row = array[r]; + for (var c = 0; c < cols; c++) { + if (c != 0) { + str += ', '; + } + var cell = row[c]; + if (cell != undefined) { + str += exports.format(cell); + } + } + } + str += ']'; + + return str; +} +*/ \ No newline at end of file diff --git a/src/util/types.js b/src/util/types.js new file mode 100644 index 000000000..7b3d39fcb --- /dev/null +++ b/src/util/types.js @@ -0,0 +1,66 @@ +/** + * Determine the type of a variable + * + * typeof(x) + * + * @param {*} x + * @return {String} type Lower case type, for example "number", "string", + * "array". + */ +exports.type = function type (x) { + var type = typeof x, + name; + + if (type == 'object') { + if (x == null) { + return 'null'; + } + if (x instanceof Boolean) { + return 'boolean'; + } + if (x instanceof Number) { + return 'number'; + } + if (x instanceof String) { + return 'string'; + } + if (Array.isArray(x)) { + return 'array'; + } + if (x instanceof Date) { + return 'date'; + } + if (x.constructor) { + // search data types + for (name in types) { + if (types.hasOwnProperty(name)) { + if (x.constructor == types[name]) { + return name.toLowerCase(); + } + } + } + + // try the constructors name as last resort + if (x.constructor.name) { + return x.constructor.name.toLowerCase(); + } + } + } + + return type; +}; + +/** + * Custom registered types, for example {'matrix': Matrix} + * @private + */ +var types = {}; + +/** + * Register a new type, for example addType('matrix', Matrix) + * @param {String} name Lower case name of the type + * @param {Function} type Prototype function of the type + */ +exports.addType = function addType (name, type) { + types[name] = type; +}; diff --git a/test/contstants.test.js b/test/contstants.test.js index 412c09e52..75b575788 100644 --- a/test/contstants.test.js +++ b/test/contstants.test.js @@ -1,5 +1,5 @@ var assert = require('assert'), - math = require('../dist/math.js'), + math = require('../src/index.js'), approx = require('../tools/approx.js'); // pi diff --git a/test/expr/parser.test.js b/test/expr/parser.test.js index 05dd03ab7..73cee2c19 100644 --- a/test/expr/parser.test.js +++ b/test/expr/parser.test.js @@ -2,7 +2,7 @@ var assert = require('assert'), approx = require('../../tools/approx.js'), - math = require('../../dist/math.js'), + math = require('../../src/index.js'); parser = math.parser(), matrix = math.matrix, range = math.range, diff --git a/test/expr/scope.test.js b/test/expr/scope.test.js index 8ba3fd372..8c5cd0d23 100644 --- a/test/expr/scope.test.js +++ b/test/expr/scope.test.js @@ -1,7 +1,7 @@ // test Scope var assert = require('assert'), approx = require('../../tools/approx.js'), - math = require('../../dist/math.js'), + math = require('../../src/index.js'), Scope = math.expr.Scope; var scope1 = new Scope(); diff --git a/test/function/arithmetic/abs.test.js b/test/function/arithmetic/abs.test.js index a4649aafc..974a1bdb9 100644 --- a/test/function/arithmetic/abs.test.js +++ b/test/function/arithmetic/abs.test.js @@ -1,35 +1,45 @@ // test abs var assert = require('assert'); -var math = require('../../../dist/math.js'); +var math = require('../../../src/index.js'); -// parser -assert.equal(math.eval('abs(-4.2)'), 4.2); +describe('abs', function () { -// number -assert.equal(math.abs(-4.2), 4.2); -assert.equal(math.abs(-3.5), 3.5); -assert.equal(math.abs(100), 100); -assert.equal(math.abs(0), 0); + it('parser', function () { + assert.equal(math.eval('abs(-4.2)'), 4.2); + }); -// complex -assert.equal(math.abs(math.complex(3, -4)), 5); + it('number', function () { + assert.equal(math.abs(-4.2), 4.2); + assert.equal(math.abs(-3.5), 3.5); + assert.equal(math.abs(100), 100); + assert.equal(math.abs(0), 0); + }); + + it('complex', function () { + assert.equal(math.abs(math.complex(3, -4)), 5); + }); + + it('unit', function () { + assert.throws(function () { + math.abs(math.unit(5, 'km')); + }); + }); + + it('string', function () { + assert.throws(function () { + math.abs('a string'); + }); + }); + + it('matrix, array', 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.range(-2,2)); + assert.ok(Array.isArray(a1)); + assert.deepEqual(a1.length, 5); + assert.deepEqual(a1, [2,1,0,1,2]) + }); -// unit -assert.throws(function () { - math.abs(math.unit(5, 'km')); }); - -// string -assert.throws(function () { - math.abs('a string'); -}); - -// matrix, array -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.range(-2,2)); -assert.ok(Array.isArray(a1)); -assert.deepEqual(a1.length, 5); -assert.deepEqual(a1, [2,1,0,1,2]); diff --git a/test/function/arithmetic/add.test.js b/test/function/arithmetic/add.test.js index 9dd05a424..b5318100f 100644 --- a/test/function/arithmetic/add.test.js +++ b/test/function/arithmetic/add.test.js @@ -1,6 +1,6 @@ // test add var assert = require('assert'); -var math = require('../../../dist/math.js'); +var math = require('../../../src/index.js'); // parser assert.equal(math.eval('add(2, 3)'), 5); diff --git a/test/function/arithmetic/ceil.test.js b/test/function/arithmetic/ceil.test.js index cc38690f7..0935ac497 100644 --- a/test/function/arithmetic/ceil.test.js +++ b/test/function/arithmetic/ceil.test.js @@ -1,7 +1,7 @@ // test ceil var assert = require('assert'), approx = require('../../../tools/approx.js'), - math = require('../../../dist/math.js'), + math = require('../../../src/index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/cube.test.js b/test/function/arithmetic/cube.test.js index fad6fb7d8..502c11acc 100644 --- a/test/function/arithmetic/cube.test.js +++ b/test/function/arithmetic/cube.test.js @@ -1,6 +1,6 @@ // test cube var assert = require('assert'), - math = require('../../../dist/math.js'), + math = require('../../../src/index.js'), unit = math.unit, matrix = math.matrix, range = math.range, diff --git a/test/function/arithmetic/divide.test.js b/test/function/arithmetic/divide.test.js index be029cacc..7c336a0c6 100644 --- a/test/function/arithmetic/divide.test.js +++ b/test/function/arithmetic/divide.test.js @@ -1,6 +1,6 @@ // test divide var assert = require('assert'); -math = require('../../../dist/math.js'), +math = require('../../../src/index.js'), approx = require('../../../tools/approx.js'), divide = math.divide, complex = math.complex; diff --git a/test/function/arithmetic/edivide.test.js b/test/function/arithmetic/edivide.test.js index 61d727a21..95fbeebe8 100644 --- a/test/function/arithmetic/edivide.test.js +++ b/test/function/arithmetic/edivide.test.js @@ -1,6 +1,6 @@ // test edivide (element-wise divide) var assert = require('assert'); -math = require('../../../dist/math.js'), +math = require('../../../src/index.js'), approx = require('../../../tools/approx.js'), edivide = math.edivide, complex = math.complex; diff --git a/test/function/arithmetic/emultiply.test.js b/test/function/arithmetic/emultiply.test.js index 4f9de50e1..7c719ab38 100644 --- a/test/function/arithmetic/emultiply.test.js +++ b/test/function/arithmetic/emultiply.test.js @@ -1,6 +1,6 @@ // test emultiply (element-wise multiply) var assert = require('assert'), - math = require('../../../dist/math.js'), + math = require('../../../src/index.js'), approx = require('../../../tools/approx.js'), emultiply = math.emultiply, divide = math.divide, diff --git a/test/function/arithmetic/epow.test.js b/test/function/arithmetic/epow.test.js index daba82cd6..66d8e6a0b 100644 --- a/test/function/arithmetic/epow.test.js +++ b/test/function/arithmetic/epow.test.js @@ -1,7 +1,7 @@ // test exp var assert = require('assert'), approx = require('../../../tools/approx.js'), - math = require('../../../dist/math.js'), + math = require('../../../src/index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/equal.test.js b/test/function/arithmetic/equal.test.js index 933db6987..74611ddc9 100644 --- a/test/function/arithmetic/equal.test.js +++ b/test/function/arithmetic/equal.test.js @@ -1,6 +1,6 @@ // test equal var assert = require('assert'), - math = require('../../../dist/math.js'), + math = require('../../../src/index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/exp.test.js b/test/function/arithmetic/exp.test.js index 1d9bc1286..f6376daaf 100644 --- a/test/function/arithmetic/exp.test.js +++ b/test/function/arithmetic/exp.test.js @@ -1,7 +1,7 @@ // test exp var assert = require('assert'), approx = require('../../../tools/approx.js'), - math = require('../../../dist/math.js'), + math = require('../../../src/index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/fix.test.js b/test/function/arithmetic/fix.test.js index b90ac2525..4c167b9ae 100644 --- a/test/function/arithmetic/fix.test.js +++ b/test/function/arithmetic/fix.test.js @@ -1,7 +1,7 @@ // test fix var assert = require('assert'), approx = require('../../../tools/approx.js'), - math = require('../../../dist/math.js'), + math = require('../../../src/index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/floor.test.js b/test/function/arithmetic/floor.test.js index 2ddc67b67..c300f2670 100644 --- a/test/function/arithmetic/floor.test.js +++ b/test/function/arithmetic/floor.test.js @@ -1,7 +1,7 @@ // test floor var assert = require('assert'), approx = require('../../../tools/approx.js'), - math = require('../../../dist/math.js'), + math = require('../../../src/index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/gcd.test.js b/test/function/arithmetic/gcd.test.js index 7ebb7c3e1..ab8ae4d90 100644 --- a/test/function/arithmetic/gcd.test.js +++ b/test/function/arithmetic/gcd.test.js @@ -1,6 +1,6 @@ // test gcd var assert = require('assert'); -var math = require('../../../dist/math.js'); +var math = require('../../../src/index.js'); // parser assert.equal(math.eval('gcd(12, 8)'), 4); diff --git a/test/function/arithmetic/larger.test.js b/test/function/arithmetic/larger.test.js index 20c3e2e9e..18bac90ee 100644 --- a/test/function/arithmetic/larger.test.js +++ b/test/function/arithmetic/larger.test.js @@ -1,6 +1,6 @@ // test larger var assert = require('assert'), - math = require('../../../dist/math.js'), + math = require('../../../src/index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/largereq.test.js b/test/function/arithmetic/largereq.test.js index bb3b3283c..fb31967cb 100644 --- a/test/function/arithmetic/largereq.test.js +++ b/test/function/arithmetic/largereq.test.js @@ -1,6 +1,6 @@ // test largereq var assert = require('assert'), - math = require('../../../dist/math.js'), + math = require('../../../src/index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/lcm.test.js b/test/function/arithmetic/lcm.test.js index 79bdec110..e9540d9d0 100644 --- a/test/function/arithmetic/lcm.test.js +++ b/test/function/arithmetic/lcm.test.js @@ -1,5 +1,5 @@ var assert = require('assert'); -var math = require('../../../dist/math.js'); +var math = require('../../../src/index.js'); // test lcm assert.equal(math.lcm(4, 6), 12); diff --git a/test/function/arithmetic/log.test.js b/test/function/arithmetic/log.test.js index 393d16a18..49282b08c 100644 --- a/test/function/arithmetic/log.test.js +++ b/test/function/arithmetic/log.test.js @@ -1,7 +1,7 @@ // test exp var assert = require('assert'), approx = require('../../../tools/approx.js'), - math = require('../../../dist/math.js'), + math = require('../../../src/index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/log10.test.js b/test/function/arithmetic/log10.test.js index fa241c2c3..32d2be17b 100644 --- a/test/function/arithmetic/log10.test.js +++ b/test/function/arithmetic/log10.test.js @@ -1,7 +1,7 @@ // test exp var assert = require('assert'), approx = require('../../../tools/approx.js'), - math = require('../../../dist/math.js'), + math = require('../../../src/index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/mod.test.js b/test/function/arithmetic/mod.test.js index 987ace00c..986773649 100644 --- a/test/function/arithmetic/mod.test.js +++ b/test/function/arithmetic/mod.test.js @@ -1,7 +1,7 @@ // test mod var assert = require('assert'), approx = require('../../../tools/approx.js'), - math = require('../../../dist/math.js'), + math = require('../../../src/index.js'), matrix = math.matrix, range = math.range, mod = math.mod; diff --git a/test/function/arithmetic/multiply.test.js b/test/function/arithmetic/multiply.test.js index 84c21f64d..d4615835a 100644 --- a/test/function/arithmetic/multiply.test.js +++ b/test/function/arithmetic/multiply.test.js @@ -1,6 +1,6 @@ // test multiply var assert = require('assert'), - math = require('../../../dist/math.js'), + math = require('../../../src/index.js'), approx = require('../../../tools/approx.js'), multiply = math.multiply, divide = math.divide, diff --git a/test/function/arithmetic/pow.test.js b/test/function/arithmetic/pow.test.js index 4e83da17f..83304e677 100644 --- a/test/function/arithmetic/pow.test.js +++ b/test/function/arithmetic/pow.test.js @@ -1,7 +1,7 @@ // test exp var assert = require('assert'), approx = require('../../../tools/approx.js'), - math = require('../../../dist/math.js'), + math = require('../../../src/index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/round.test.js b/test/function/arithmetic/round.test.js index 089c55469..0fcfefd84 100644 --- a/test/function/arithmetic/round.test.js +++ b/test/function/arithmetic/round.test.js @@ -1,6 +1,6 @@ // test round var assert = require('assert'); -var math = require('../../../dist/math.js'); +var math = require('../../../src/index.js'); // parser assert.equal(math.eval('round(pi)'), 3); diff --git a/test/function/arithmetic/sign.test.js b/test/function/arithmetic/sign.test.js index 6c1060283..95e561e5a 100644 --- a/test/function/arithmetic/sign.test.js +++ b/test/function/arithmetic/sign.test.js @@ -1,6 +1,6 @@ // test sign var assert = require('assert'); -var math = require('../../../dist/math.js'); +var math = require('../../../src/index.js'); // parser assert.equal(math.eval('sign(3)'), 1); diff --git a/test/function/arithmetic/smaller.test.js b/test/function/arithmetic/smaller.test.js index f25ab84ad..e5843b55f 100644 --- a/test/function/arithmetic/smaller.test.js +++ b/test/function/arithmetic/smaller.test.js @@ -1,6 +1,6 @@ // test smaller var assert = require('assert'), - math = require('../../../dist/math.js'), + math = require('../../../src/index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/smallereq.test.js b/test/function/arithmetic/smallereq.test.js index 25a3ec4c1..695c81dbc 100644 --- a/test/function/arithmetic/smallereq.test.js +++ b/test/function/arithmetic/smallereq.test.js @@ -1,6 +1,6 @@ // test smaller var assert = require('assert'), - math = require('../../../dist/math.js'), + math = require('../../../src/index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/sqrt.test.js b/test/function/arithmetic/sqrt.test.js index 9d8cc82be..d5d0b206f 100644 --- a/test/function/arithmetic/sqrt.test.js +++ b/test/function/arithmetic/sqrt.test.js @@ -1,7 +1,7 @@ // test sqrt var assert = require('assert'), approx = require('../../../tools/approx.js'), - math = require('../../../dist/math.js'); + math = require('../../../src/index.js'); // parser assert.equal(math.eval('sqrt(25)'), 5); diff --git a/test/function/arithmetic/square.test.js b/test/function/arithmetic/square.test.js index 386d8c3f0..55141cb65 100644 --- a/test/function/arithmetic/square.test.js +++ b/test/function/arithmetic/square.test.js @@ -1,6 +1,6 @@ // test square var assert = require('assert'), - math = require('../../../dist/math.js'), + math = require('../../../src/index.js'), unit = math.unit, matrix = math.matrix, range = math.range, diff --git a/test/function/arithmetic/subtract.test.js b/test/function/arithmetic/subtract.test.js index 0c215f86c..9e92ba48b 100644 --- a/test/function/arithmetic/subtract.test.js +++ b/test/function/arithmetic/subtract.test.js @@ -1,6 +1,6 @@ // test subtract var assert = require('assert'); -var math = require('../../../dist/math.js'); +var math = require('../../../src/index.js'); // parser assert.equal(math.eval('4 - 2'), 2); diff --git a/test/function/arithmetic/unaryminus.test.js b/test/function/arithmetic/unaryminus.test.js index aa7979450..2e15c6bb9 100644 --- a/test/function/arithmetic/unaryminus.test.js +++ b/test/function/arithmetic/unaryminus.test.js @@ -1,6 +1,6 @@ // test unary minus var assert = require('assert'); -var math = require('../../../dist/math.js'); +var math = require('../../../src/index.js'); // parser assert.equal(math.eval('-2'), -2); diff --git a/test/function/arithmetic/unequal.test.js b/test/function/arithmetic/unequal.test.js index 9c873a85c..78137aab6 100644 --- a/test/function/arithmetic/unequal.test.js +++ b/test/function/arithmetic/unequal.test.js @@ -1,6 +1,6 @@ // test equal var assert = require('assert'), - math = require('../../../dist/math.js'), + math = require('../../../src/index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/arithmetic/xgcd.test.js b/test/function/arithmetic/xgcd.test.js index fbbf1cc82..922d89dea 100644 --- a/test/function/arithmetic/xgcd.test.js +++ b/test/function/arithmetic/xgcd.test.js @@ -1,6 +1,6 @@ // test xgcd var assert = require('assert'); -var math = require('../../../dist/math.js'); +var math = require('../../../src/index.js'); // parser assert.deepEqual([1247, -7, 12], math.eval('xgcd(36163, 21199)')); diff --git a/test/function/complex/arg.test.js b/test/function/complex/arg.test.js index 8259a9b4a..b3d3cb5d4 100644 --- a/test/function/complex/arg.test.js +++ b/test/function/complex/arg.test.js @@ -1,6 +1,6 @@ // test arg var assert = require('assert'); -var math = require('../../../dist/math.js'); +var math = require('../../../src/index.js'); assert.equal(math.arg(math.complex('0')) / math.pi, 0); assert.equal(math.arg(math.complex('1 + 0i')) / math.pi, 0); diff --git a/test/function/complex/conj.test.js b/test/function/complex/conj.test.js index ca7a96ad4..01292bd81 100644 --- a/test/function/complex/conj.test.js +++ b/test/function/complex/conj.test.js @@ -1,6 +1,6 @@ // test conj var assert = require('assert'); -var math = require('../../../dist/math.js'); +var math = require('../../../src/index.js'); assert.equal(math.conj(math.complex('2 + 3i')).toString(), '2 - 3i'); assert.equal(math.conj(123).toString(), '123'); @@ -12,5 +12,6 @@ assert.equal(math.format(math.conj([math.complex('2+3i'), math.complex('3-4i')]) '[2 - 3i, 3 + 4i]'); assert.equal(math.conj(math.matrix([math.complex('2+3i'), math.complex('3-4i')])).toString(), '[2 - 3i, 3 + 4i]'); -assert.throws(function() {math.conj('string') }); -assert.throws(function() {math.conj(math.unit('5cm')) }); + +assert.equal(math.conj('string'), 'string'); +assert.deepEqual(math.conj(math.unit('5cm')), math.unit('5cm')); diff --git a/test/function/complex/im.test.js b/test/function/complex/im.test.js index 833d56e19..7c460f806 100644 --- a/test/function/complex/im.test.js +++ b/test/function/complex/im.test.js @@ -1,6 +1,6 @@ // test im var assert = require('assert'); -var math = require('../../../dist/math.js'); +var math = require('../../../src/index.js'); assert.equal(math.im(math.complex(2,3)), 3); assert.equal(math.im(math.complex(-2,-3)), -3); diff --git a/test/function/complex/re.test.js b/test/function/complex/re.test.js index ec8343663..d5a16c31a 100644 --- a/test/function/complex/re.test.js +++ b/test/function/complex/re.test.js @@ -1,6 +1,6 @@ // test re var assert = require('assert'); -var math = require('../../../dist/math.js'); +var math = require('../../../src/index.js'); assert.equal(math.re(math.complex(2,3)), 2); assert.equal(math.re(math.complex(-2,-3)), -2); diff --git a/test/function/construction/boolean.test.js b/test/function/construction/boolean.test.js index 367c503a9..e0144f7df 100644 --- a/test/function/construction/boolean.test.js +++ b/test/function/construction/boolean.test.js @@ -1,6 +1,6 @@ // test bool construction var assert = require('assert'), - math = require('../../../dist/math.js'), + math = require('../../../src/index.js'), bool = math.boolean; // parser diff --git a/test/function/construction/complex.test.js b/test/function/construction/complex.test.js index 3f85cedbc..57eac69d5 100644 --- a/test/function/construction/complex.test.js +++ b/test/function/construction/complex.test.js @@ -1,6 +1,6 @@ // test complex construction var assert = require('assert'), - math = require('../../../dist/math.js'), + math = require('../../../src/index.js'), complex = math.complex; // 0 arguments diff --git a/test/function/construction/matrix.test.js b/test/function/construction/matrix.test.js index 198bd34a0..c31a9e21e 100644 --- a/test/function/construction/matrix.test.js +++ b/test/function/construction/matrix.test.js @@ -1,6 +1,6 @@ // test matrix construction var assert = require('assert'), - math = require('../../../dist/math.js'), + math = require('../../../src/index.js'), matrix = math.matrix; // 0 arguments diff --git a/test/function/construction/number.test.js b/test/function/construction/number.test.js index bfd68f85c..f13a9ca91 100644 --- a/test/function/construction/number.test.js +++ b/test/function/construction/number.test.js @@ -1,6 +1,6 @@ // test number construction var assert = require('assert'), - math = require('../../../dist/math.js'), + math = require('../../../src/index.js'), approx = require('../../../tools/approx.js'), number = math.number; diff --git a/test/function/construction/range.test.js b/test/function/construction/range.test.js index fb8a9a871..a26e07b64 100644 --- a/test/function/construction/range.test.js +++ b/test/function/construction/range.test.js @@ -1,6 +1,6 @@ // test range construction var assert = require('assert'), - math = require('../../../dist/math.js'), + math = require('../../../src/index.js'), range = math.range; diff --git a/test/function/construction/string.test.js b/test/function/construction/string.test.js index de5aee4db..83208525b 100644 --- a/test/function/construction/string.test.js +++ b/test/function/construction/string.test.js @@ -1,6 +1,6 @@ // test string construction var assert = require('assert'), - math = require('../../../dist/math.js'), + math = require('../../../src/index.js'), string = math.string; // parser @@ -25,7 +25,7 @@ assert.equal(string(' '), ' '); // number assert.equal(string(1/8), '0.125'); assert.equal(string(2.1e-3), '0.0021'); -assert.equal(string(123456789), '1.23456789e8'); +assert.equal(string(123456789), '1.2346e8'); // TODO: is it desirable that value is rounded? assert.equal(string(2000000), '2e6'); // complex diff --git a/test/function/construction/unit.test.js b/test/function/construction/unit.test.js index 2ec52942a..b0f3c861c 100644 --- a/test/function/construction/unit.test.js +++ b/test/function/construction/unit.test.js @@ -1,6 +1,6 @@ // test unit construction var assert = require('assert'), - math = require('../../../dist/math.js'), + math = require('../../../src/index.js'), unit = math.unit; diff --git a/test/function/example.test.js b/test/function/example.test.js index e7ebcab5f..cf008df30 100644 --- a/test/function/example.test.js +++ b/test/function/example.test.js @@ -2,8 +2,8 @@ return; var assert = require('assert'), - approx = require('../../../tools/approx.js'), - math = require('../../../math.js'), + approx = require('../../tools/approx.js'), + math = require('../../src/index.js'), complex = math.complex, matrix = math.matrix, unit = math.unit, diff --git a/test/function/matrix/concat.test.js b/test/function/matrix/concat.test.js index 79bf4a920..f0dd2e903 100644 --- a/test/function/matrix/concat.test.js +++ b/test/function/matrix/concat.test.js @@ -1,6 +1,6 @@ // test concat var assert = require('assert'); -var math = require('../../../dist/math.js'); +var math = require('../../../src/index.js'); assert.deepEqual(math.concat([1,2,3], [4]), [1,2,3,4]); assert.deepEqual(math.concat([[1],[2],[3]], [[4]], 0), [[1],[2],[3],[4]]); diff --git a/test/function/matrix/det.test.js b/test/function/matrix/det.test.js index 3e17871e0..83419a600 100644 --- a/test/function/matrix/det.test.js +++ b/test/function/matrix/det.test.js @@ -1,6 +1,6 @@ // test det var assert = require('assert'); -var math = require('../../../dist/math.js'); +var math = require('../../../src/index.js'); assert.equal(math.det(3), 3); assert.equal(math.det([5]), 5); diff --git a/test/function/matrix/diag.test.js b/test/function/matrix/diag.test.js index 0225b2fd3..1990b5468 100644 --- a/test/function/matrix/diag.test.js +++ b/test/function/matrix/diag.test.js @@ -1,5 +1,5 @@ var assert = require('assert'); -var math = require('../../../dist/math.js'); +var math = require('../../../src/index.js'); // test diag assert.deepEqual(math.diag([1,2,3]).valueOf(), [[1,0,0],[0,2,0],[0,0,3]]); diff --git a/test/function/matrix/eye.test.js b/test/function/matrix/eye.test.js index 95e2828eb..cb57810ef 100644 --- a/test/function/matrix/eye.test.js +++ b/test/function/matrix/eye.test.js @@ -1,6 +1,6 @@ // test eye var assert = require('assert'); -var math = require('../../../dist/math.js'); +var math = require('../../../src/index.js'); assert.deepEqual(math.eye().valueOf(), [[1]]); assert.deepEqual(math.eye([]).valueOf(), [[1]]); diff --git a/test/function/matrix/inv.test.js b/test/function/matrix/inv.test.js index 80f5b70cf..d46540abf 100644 --- a/test/function/matrix/inv.test.js +++ b/test/function/matrix/inv.test.js @@ -1,6 +1,6 @@ // test inv var assert = require('assert'); -var math = require('../../../dist/math.js'); +var math = require('../../../src/index.js'); assert.deepEqual(math.inv(4), 1/4); assert.deepEqual(math.inv([4]), [1/4]); diff --git a/test/function/matrix/ones.test.js b/test/function/matrix/ones.test.js index 811f44a89..2293cd113 100644 --- a/test/function/matrix/ones.test.js +++ b/test/function/matrix/ones.test.js @@ -1,6 +1,6 @@ // test ones var assert = require('assert'); -var math = require('../../../dist/math.js'); +var math = require('../../../src/index.js'); assert.deepEqual(math.ones().valueOf(), [[1]]); assert.deepEqual(math.ones([]).valueOf(), [[1]]); diff --git a/test/function/matrix/size.test.js b/test/function/matrix/size.test.js index 8faa1f33c..391c05127 100644 --- a/test/function/matrix/size.test.js +++ b/test/function/matrix/size.test.js @@ -1,6 +1,6 @@ // test size var assert = require('assert'); -var math = require('../../../dist/math.js'); +var math = require('../../../src/index.js'); assert.deepEqual(math.size([[1,2,3],[4,5,6]]), [2,3]); assert.deepEqual(math.size([[[1,2],[3,4]],[[5,6],[7,8]]]), [2,2,2]); diff --git a/test/function/matrix/squeeze.test.js b/test/function/matrix/squeeze.test.js index 58fff02d2..8e054bf51 100644 --- a/test/function/matrix/squeeze.test.js +++ b/test/function/matrix/squeeze.test.js @@ -1,6 +1,6 @@ // test squeeze var assert = require('assert'); -var math = require('../../../dist/math.js'), +var math = require('../../../src/index.js'), squeeze = math.squeeze, size = math.size, matrix = math.matrix; diff --git a/test/function/utils/subset.test.js b/test/function/matrix/subset.test.js similarity index 99% rename from test/function/utils/subset.test.js rename to test/function/matrix/subset.test.js index f9c0a650a..cebe39599 100644 --- a/test/function/utils/subset.test.js +++ b/test/function/matrix/subset.test.js @@ -1,6 +1,6 @@ // test subset var assert = require('assert'), - math = require('../../../dist/math.js'), + math = require('../../../src/index.js'), subset = math.subset, matrix = math.matrix, range = math.range; diff --git a/test/function/matrix/transpose.test.js b/test/function/matrix/transpose.test.js index 152008730..3e91c76ce 100644 --- a/test/function/matrix/transpose.test.js +++ b/test/function/matrix/transpose.test.js @@ -1,6 +1,6 @@ // test transpose var assert = require('assert'); -var math = require('../../../dist/math.js'); +var math = require('../../../src/index.js'); assert.deepEqual(math.transpose(3), 3); assert.deepEqual(math.transpose([1,2,3]), [1,2,3]); diff --git a/test/function/matrix/zeros.test.js b/test/function/matrix/zeros.test.js index 0ecfc9e49..a9595d2ec 100644 --- a/test/function/matrix/zeros.test.js +++ b/test/function/matrix/zeros.test.js @@ -1,6 +1,6 @@ // test zeros var assert = require('assert'); -var math = require('../../../dist/math.js'); +var math = require('../../../src/index.js'); assert.deepEqual(math.zeros().valueOf(), [[0]]); assert.deepEqual(math.zeros([]).valueOf(), [[0]]); diff --git a/test/function/probability/factorial.test.js b/test/function/probability/factorial.test.js index 9723a7145..278ed639f 100644 --- a/test/function/probability/factorial.test.js +++ b/test/function/probability/factorial.test.js @@ -1,6 +1,6 @@ // test factorial var assert = require('assert'); -var math = require('../../../dist/math.js'); +var math = require('../../../src/index.js'); assert.equal(math.factorial(0), 1); assert.equal(math.factorial(1), 1); diff --git a/test/function/probability/random.test.js b/test/function/probability/random.test.js index db9292982..e210a25bf 100644 --- a/test/function/probability/random.test.js +++ b/test/function/probability/random.test.js @@ -1,6 +1,6 @@ var assert = require('assert'), _ = require('underscore'), - math = require('../../../dist/math.js'); + math = require('../../../src/index.js'); var assertApproxEqual = function(testVal, val, tolerance) { var diff = Math.abs(val - testVal) diff --git a/test/function/statistics/max.test.js b/test/function/statistics/max.test.js index 538d624fc..c8fca906a 100644 --- a/test/function/statistics/max.test.js +++ b/test/function/statistics/max.test.js @@ -1,6 +1,6 @@ // test max var assert = require('assert'); -var math = require('../../../dist/math.js'); +var math = require('../../../src/index.js'); assert.equal(math.max(5), 5); assert.equal(math.max(3,1), 3); diff --git a/test/function/statistics/min.test.js b/test/function/statistics/min.test.js index 3f5082a9a..fcd2b7f06 100644 --- a/test/function/statistics/min.test.js +++ b/test/function/statistics/min.test.js @@ -1,6 +1,6 @@ // test min var assert = require('assert'); -var math = require('../../../dist/math.js'); +var math = require('../../../src/index.js'); assert.equal(math.min(5), 5); assert.equal(math.min(1,3), 1); diff --git a/test/function/trigonometry/acos.test.js b/test/function/trigonometry/acos.test.js index fa8a73c98..d4c14871a 100644 --- a/test/function/trigonometry/acos.test.js +++ b/test/function/trigonometry/acos.test.js @@ -1,6 +1,6 @@ // test acos var assert = require('assert'), - math = require('../../../dist/math.js'), + math = require('../../../src/index.js'), approx = require('../../../tools/approx.js'), pi = math.pi, acos = math.acos, diff --git a/test/function/trigonometry/asin.test.js b/test/function/trigonometry/asin.test.js index 25015bb83..f7e94a0db 100644 --- a/test/function/trigonometry/asin.test.js +++ b/test/function/trigonometry/asin.test.js @@ -1,6 +1,6 @@ // test asin var assert = require('assert'), - math = require('../../../dist/math.js'), + math = require('../../../src/index.js'), approx = require('../../../tools/approx.js'), pi = math.pi, complex = math.complex, diff --git a/test/function/trigonometry/atan.test.js b/test/function/trigonometry/atan.test.js index b6d297e47..dac466343 100644 --- a/test/function/trigonometry/atan.test.js +++ b/test/function/trigonometry/atan.test.js @@ -1,6 +1,6 @@ // test atan var assert = require('assert'), - math = require('../../../dist/math.js'), + math = require('../../../src/index.js'), approx = require('../../../tools/approx.js'), pi = math.pi, complex = math.complex, diff --git a/test/function/trigonometry/atan2.test.js b/test/function/trigonometry/atan2.test.js index 5afab1eb1..9a151583a 100644 --- a/test/function/trigonometry/atan2.test.js +++ b/test/function/trigonometry/atan2.test.js @@ -1,6 +1,6 @@ // test atan2 var assert = require('assert'), - math = require('../../../dist/math.js'), + math = require('../../../src/index.js'), approx = require('../../../tools/approx.js'), pi = math.pi, acos = math.acos, diff --git a/test/function/trigonometry/cos.test.js b/test/function/trigonometry/cos.test.js index 2e5acd02a..941227459 100644 --- a/test/function/trigonometry/cos.test.js +++ b/test/function/trigonometry/cos.test.js @@ -1,6 +1,6 @@ // test cos var assert = require('assert'), - math = require('../../../dist/math.js'), + math = require('../../../src/index.js'), approx = require('../../../tools/approx.js'), pi = math.pi, complex = math.complex, diff --git a/test/function/trigonometry/cot.test.js b/test/function/trigonometry/cot.test.js index ca4da7cac..af1034e27 100644 --- a/test/function/trigonometry/cot.test.js +++ b/test/function/trigonometry/cot.test.js @@ -1,6 +1,6 @@ // test cot var assert = require('assert'), - math = require('../../../dist/math.js'), + math = require('../../../src/index.js'), approx = require('../../../tools/approx.js'), pi = math.pi, complex = math.complex, diff --git a/test/function/trigonometry/csc.test.js b/test/function/trigonometry/csc.test.js index edea41a4e..6314e6e58 100644 --- a/test/function/trigonometry/csc.test.js +++ b/test/function/trigonometry/csc.test.js @@ -1,6 +1,6 @@ // test csc var assert = require('assert'), - math = require('../../../dist/math.js'), + math = require('../../../src/index.js'), approx = require('../../../tools/approx.js'), pi = math.pi, complex = math.complex, diff --git a/test/function/trigonometry/sec.test.js b/test/function/trigonometry/sec.test.js index 6e7f3eec5..e27300fd5 100644 --- a/test/function/trigonometry/sec.test.js +++ b/test/function/trigonometry/sec.test.js @@ -1,6 +1,6 @@ // test sec var assert = require('assert'), - math = require('../../../dist/math.js'), + math = require('../../../src/index.js'), approx = require('../../../tools/approx.js'), pi = math.pi, complex = math.complex, diff --git a/test/function/trigonometry/sin.test.js b/test/function/trigonometry/sin.test.js index b4f4afa4c..3f9b740c7 100644 --- a/test/function/trigonometry/sin.test.js +++ b/test/function/trigonometry/sin.test.js @@ -1,6 +1,6 @@ // test sin var assert = require('assert'), - math = require('../../../dist/math.js'), + math = require('../../../src/index.js'), approx = require('../../../tools/approx.js'), pi = math.pi, complex = math.complex, diff --git a/test/function/trigonometry/tan.test.js b/test/function/trigonometry/tan.test.js index 53efb264e..743af9782 100644 --- a/test/function/trigonometry/tan.test.js +++ b/test/function/trigonometry/tan.test.js @@ -1,6 +1,6 @@ // test tan var assert = require('assert'), - math = require('../../../dist/math.js'), + math = require('../../../src/index.js'), approx = require('../../../tools/approx.js'), pi = math.pi, complex = math.complex, diff --git a/test/function/units/in.test.js b/test/function/units/in.test.js index 04f2d5733..f7276359c 100644 --- a/test/function/units/in.test.js +++ b/test/function/units/in.test.js @@ -2,7 +2,7 @@ var assert = require('assert'), approx = require('../../../tools/approx.js'), - math = require('../../../dist/math.js'), + math = require('../../../src/index.js'), unit = math.unit; // test function in diff --git a/test/function/utils/clone.test.js b/test/function/utils/clone.test.js index 375927d34..8a3e72a52 100644 --- a/test/function/utils/clone.test.js +++ b/test/function/utils/clone.test.js @@ -1,6 +1,6 @@ // test clone var assert = require('assert'); -var math = require('../../../dist/math.js'); +var math = require('../../../src/index.js'); var a = 1; var b = math.clone(a); diff --git a/test/function/utils/eval.test.js b/test/function/utils/eval.test.js index 22185cb84..d5006c6a3 100644 --- a/test/function/utils/eval.test.js +++ b/test/function/utils/eval.test.js @@ -1,6 +1,6 @@ // test eval var assert = require('assert'); -var math = require('../../../dist/math.js'); +var math = require('../../../src/index.js'); // test some expressions assert.equal(math.eval('pi'), Math.PI); diff --git a/test/function/utils/format.test.js b/test/function/utils/format.test.js index 9da9e3cbf..b790205f3 100644 --- a/test/function/utils/format.test.js +++ b/test/function/utils/format.test.js @@ -1,6 +1,6 @@ // test format var assert = require('assert'); -var math = require('../../../dist/math.js'); +var math = require('../../../src/index.js'); assert.equal(math.format(2/7), '0.28571'); assert.equal(math.format(0.10400), '0.104'); diff --git a/test/function/utils/help.test.js b/test/function/utils/help.test.js index 0cf5e24a5..5353b3fd7 100644 --- a/test/function/utils/help.test.js +++ b/test/function/utils/help.test.js @@ -1,6 +1,6 @@ // test help var assert = require('assert'); -var math = require('../../../dist/math.js'); +var math = require('../../../src/index.js'); var prop; var doc = math.help('sin'); diff --git a/test/function/utils/import.test.js b/test/function/utils/import.test.js index 1ff2d4355..8a5a1f8d0 100644 --- a/test/function/utils/import.test.js +++ b/test/function/utils/import.test.js @@ -1,6 +1,6 @@ // test import var assert = require('assert'), - math = require('../../../dist/math.js'), + math = require('../../../src/index.js'), approx = require('../../../tools/approx.js'); math.import({ diff --git a/test/function/utils/parse.test.js b/test/function/utils/parse.test.js index 287b9635d..982782d11 100644 --- a/test/function/utils/parse.test.js +++ b/test/function/utils/parse.test.js @@ -1,6 +1,6 @@ // test parse var assert = require('assert'); -var math = require('../../../dist/math.js'); +var math = require('../../../src/index.js'); // test some expressions assert.ok(math.parse('pi') instanceof math.expr.node.Node); diff --git a/test/function/utils/select.test.js b/test/function/utils/select.test.js index be21e5d49..686ec911b 100644 --- a/test/function/utils/select.test.js +++ b/test/function/utils/select.test.js @@ -1,9 +1,9 @@ // test select (chaining of operations) var assert = require('assert'), approx = require('../../../tools/approx.js'), - math = require('../../../dist/math.js'); + math = require('../../../src/index.js'); -assert.ok(math.select(45) instanceof math.type.Selector); +assert.ok(math.select(45) instanceof math.expr.Selector); assert.equal(math.select(3).add(4).subtract(2).done(), 5); assert.deepEqual(math.select(math.matrix([[1,2],[3,4]])) .set([0,0], 8) diff --git a/test/function/utils/typeof.test.js b/test/function/utils/typeof.test.js index 08237e308..579a6cd43 100644 --- a/test/function/utils/typeof.test.js +++ b/test/function/utils/typeof.test.js @@ -1,6 +1,6 @@ // test typeof var assert = require('assert'); -var math = require('../../../dist/math.js'); +var math = require('../../../src/index.js'); assert.equal(math.typeof(2), 'number'); assert.equal(math.typeof(new Number(2)), 'number'); diff --git a/test/type/complex.test.js b/test/type/complex.test.js index 71e2a556e..280d0238a 100644 --- a/test/type/complex.test.js +++ b/test/type/complex.test.js @@ -1,87 +1,98 @@ // test data type Complex var assert = require('assert'); -var math = require('../../dist/math.js'); +var math = require('../../src/index.js'); -var complex1 = math.complex(3, -4); -assert.equal(complex1.re, 3); -assert.equal(complex1.im, -4); -assert.equal(complex1, '3 - 4i'); -assert.throws(function () { Complex(3, -4); }); +describe('Complex', function () { -// test constructor and parser -assert.equal(math.complex().toString(), '0'); -assert.equal(math.complex(2, 3).toString(), '2 + 3i'); -assert.equal(math.complex(2, 0).toString(), '2'); -assert.equal(math.complex(0, 3).toString(), '3i'); -assert.equal(math.complex('2 + 3i').toString(), '2 + 3i'); -assert.equal(math.complex('2 +3i').toString(), '2 + 3i'); -assert.equal(math.complex('2+3i').toString(), '2 + 3i'); -assert.equal(math.complex(' 2+3i ').toString(), '2 + 3i'); -assert.equal(math.complex('2-3i').toString(), '2 - 3i'); -assert.equal(math.complex('2 + i').toString(), '2 + i'); -assert.equal(math.complex('-2-3i').toString(), '-2 - 3i'); -assert.equal(math.complex('-2+3i').toString(), '-2 + 3i'); -assert.equal(math.complex('-2+-3i').toString(), '-2 - 3i'); -assert.equal(math.complex('-2-+3i').toString(), '-2 - 3i'); -assert.equal(math.complex('+2-+3i').toString(), '2 - 3i'); -assert.equal(math.complex('+2-+3i').toString(), '2 - 3i'); -assert.equal(math.complex('2 + 3i').toString(), '2 + 3i'); -assert.equal(math.complex('2 - -3i').toString(), '2 + 3i'); -assert.equal(math.complex(' 2 + 3i ').toString(), '2 + 3i'); -assert.equal(math.complex('2 + i').toString(), '2 + i'); -assert.equal(math.complex('2 - i').toString(), '2 - i'); -assert.equal(math.complex('2 + -i').toString(), '2 - i'); -assert.equal(math.complex('-2+3e-1i').toString(), '-2 + 0.3i'); -assert.equal(math.complex('-2+3e+1i').toString(), '-2 + 30i'); -assert.equal(math.complex('2+3e2i').toString(), '2 + 300i'); -assert.equal(math.complex('2.2e-1-3.2e-1i').toString(), '0.22 - 0.32i'); -assert.equal(math.complex('2.2e-1-+3.2e-1i').toString(), '0.22 - 0.32i'); -assert.equal(math.complex('2').toString(), '2'); -assert.equal(math.complex('i').toString(), 'i'); -assert.equal(math.complex(' i ').toString(), 'i'); -assert.equal(math.complex('-i').toString(), '-i'); -assert.equal(math.complex(' -i ').toString(), '-i'); -assert.equal(math.complex('+i').toString(), 'i'); -assert.equal(math.complex(' +i ').toString(), 'i'); -assert.equal(math.complex('-2').toString(), '-2'); -assert.equal(math.complex('3I').toString(), '3i'); -assert.equal(math.complex('-3i').toString(), '-3i'); -assert.throws(function () { math.complex(1, 2, 3); }); -assert.throws(function () { math.complex('str', 2); }); -assert.throws(function () { math.complex(1, true); }); -assert.throws(function () { math.complex(2); }); -assert.throws(function () { math.complex(''); }); -assert.throws(function () { math.complex('2r'); }); -assert.throws(function () { math.complex('str'); }); -assert.throws(function () { math.complex('2i+3i'); }); -assert.throws(function () { math.complex('2ia'); }); -assert.throws(function () { math.complex('3+4'); }); -assert.throws(function () { math.complex('3i+4'); }); -assert.throws(function () { math.complex('3e + 4i'); }); -assert.throws(function () { math.complex('3e1.2 + 4i'); }); -assert.throws(function () { math.complex('3e1.2i'); }); -assert.throws(function () { math.complex('3e1.2i'); }); -assert.throws(function () { math.complex('- i'); }); -assert.throws(function () { math.complex('+ i'); }); + it('creation', function () { + var complex1 = math.complex(3, -4); + assert.equal(complex1.re, 3); + assert.equal(complex1.im, -4); + assert.equal(complex1.toString(), '3 - 4i'); + assert.throws(function () { math.complex(3, -4, 5); }); + assert.throws(function () { math.type.Complex(3, -4); }); // no new + }); -// test toString -assert.equal(math.complex().toString(), '0'); -assert.equal(math.complex(0, 2).toString(), '2i'); -assert.equal(math.complex(1, 1).toString(), '1 + i'); -assert.equal(math.complex(1, 2).toString(), '1 + 2i'); -assert.equal(math.complex(1, -1).toString(), '1 - i'); -assert.equal(math.complex(1, -2).toString(), '1 - 2i'); -assert.equal(math.complex(1, 0).toString(), '1'); -assert.equal(math.complex(-1, 2).toString(), '-1 + 2i'); -assert.equal(math.complex(-1, 1).toString(), '-1 + i'); + it('constructor and parser', function () { + assert.equal(math.complex().toString(), '0'); + assert.equal(math.complex(2, 3).toString(), '2 + 3i'); + assert.equal(math.complex(2, 0).toString(), '2'); + assert.equal(math.complex(0, 3).toString(), '3i'); + assert.equal(math.complex('2 + 3i').toString(), '2 + 3i'); + assert.equal(math.complex('2 +3i').toString(), '2 + 3i'); + assert.equal(math.complex('2+3i').toString(), '2 + 3i'); + assert.equal(math.complex(' 2+3i ').toString(), '2 + 3i'); + assert.equal(math.complex('2-3i').toString(), '2 - 3i'); + assert.equal(math.complex('2 + i').toString(), '2 + i'); + assert.equal(math.complex('-2-3i').toString(), '-2 - 3i'); + assert.equal(math.complex('-2+3i').toString(), '-2 + 3i'); + assert.equal(math.complex('-2+-3i').toString(), '-2 - 3i'); + assert.equal(math.complex('-2-+3i').toString(), '-2 - 3i'); + assert.equal(math.complex('+2-+3i').toString(), '2 - 3i'); + assert.equal(math.complex('+2-+3i').toString(), '2 - 3i'); + assert.equal(math.complex('2 + 3i').toString(), '2 + 3i'); + assert.equal(math.complex('2 - -3i').toString(), '2 + 3i'); + assert.equal(math.complex(' 2 + 3i ').toString(), '2 + 3i'); + assert.equal(math.complex('2 + i').toString(), '2 + i'); + assert.equal(math.complex('2 - i').toString(), '2 - i'); + assert.equal(math.complex('2 + -i').toString(), '2 - i'); + assert.equal(math.complex('-2+3e-1i').toString(), '-2 + 0.3i'); + assert.equal(math.complex('-2+3e+1i').toString(), '-2 + 30i'); + assert.equal(math.complex('2+3e2i').toString(), '2 + 300i'); + assert.equal(math.complex('2.2e-1-3.2e-1i').toString(), '0.22 - 0.32i'); + assert.equal(math.complex('2.2e-1-+3.2e-1i').toString(), '0.22 - 0.32i'); + assert.equal(math.complex('2').toString(), '2'); + assert.equal(math.complex('i').toString(), 'i'); + assert.equal(math.complex(' i ').toString(), 'i'); + assert.equal(math.complex('-i').toString(), '-i'); + assert.equal(math.complex(' -i ').toString(), '-i'); + assert.equal(math.complex('+i').toString(), 'i'); + assert.equal(math.complex(' +i ').toString(), 'i'); + assert.equal(math.complex('-2').toString(), '-2'); + assert.equal(math.complex('3I').toString(), '3i'); + assert.equal(math.complex('-3i').toString(), '-3i'); + assert.throws(function () { math.complex(1, 2, 3); }); + assert.throws(function () { math.complex('str', 2); }); + assert.throws(function () { math.complex(1, true); }); + assert.throws(function () { math.complex(2); }); + assert.throws(function () { math.complex(''); }); + assert.throws(function () { math.complex('2r'); }); + assert.throws(function () { math.complex('str'); }); + assert.throws(function () { math.complex('2i+3i'); }); + assert.throws(function () { math.complex('2ia'); }); + assert.throws(function () { math.complex('3+4'); }); + assert.throws(function () { math.complex('3i+4'); }); + assert.throws(function () { math.complex('3e + 4i'); }); + assert.throws(function () { math.complex('3e1.2 + 4i'); }); + assert.throws(function () { math.complex('3e1.2i'); }); + assert.throws(function () { math.complex('3e1.2i'); }); + assert.throws(function () { math.complex('- i'); }); + assert.throws(function () { math.complex('+ i'); }); + }); -// test clone -var clone = complex1.clone(); -clone.re = 100; -clone.im = 200; -assert.notEqual(complex1, clone); -assert.equal(complex1.re, 3); -assert.equal(complex1.im, -4); -assert.equal(clone.re, 100); -assert.equal(clone.im, 200); + it('toString', function () { + assert.equal(math.complex().toString(), '0'); + assert.equal(math.complex(0, 2).toString(), '2i'); + assert.equal(math.complex(1, 1).toString(), '1 + i'); + assert.equal(math.complex(1, 2).toString(), '1 + 2i'); + assert.equal(math.complex(1, -1).toString(), '1 - i'); + assert.equal(math.complex(1, -2).toString(), '1 - 2i'); + assert.equal(math.complex(1, 0).toString(), '1'); + assert.equal(math.complex(-1, 2).toString(), '-1 + 2i'); + assert.equal(math.complex(-1, 1).toString(), '-1 + i'); + }); + + it('clone', function () { + var complex1 = math.complex(3, -4); + var clone = complex1.clone(); + clone.re = 100; + clone.im = 200; + assert.notEqual(complex1, clone); + assert.equal(complex1.re, 3); + assert.equal(complex1.im, -4); + assert.equal(clone.re, 100); + assert.equal(clone.im, 200); + }); + +}); \ No newline at end of file diff --git a/test/type/help.test.js b/test/type/help.test.js index 1bc53db47..2dc28c997 100644 --- a/test/type/help.test.js +++ b/test/type/help.test.js @@ -1,6 +1,6 @@ // test Help var assert = require('assert'); -var math = require('../../dist/math.js'); +var math = require('../../src/index.js'); var help = new math.type.Help(math.docs.sin); diff --git a/test/type/matrix.test.js b/test/type/matrix.test.js index 133b06cfc..538c3de1c 100644 --- a/test/type/matrix.test.js +++ b/test/type/matrix.test.js @@ -1,7 +1,7 @@ // test data type Matrix var assert = require('assert'); -var math = require('../../dist/math.js'); +var math = require('../../src/index.js'); var m = math.matrix(); assert.equal(m.isScalar(), true); diff --git a/test/type/range.test.js b/test/type/range.test.js index efcd85ee2..f704c320f 100644 --- a/test/type/range.test.js +++ b/test/type/range.test.js @@ -1,7 +1,7 @@ // test data type Range var assert = require('assert'); -var math = require('../../dist/math.js'); +var math = require('../../src/index.js'); var r = math.range(2,5); assert.deepEqual(r.toArray(), [2,3,4,5]); diff --git a/test/type/unit.test.js b/test/type/unit.test.js index 12eff5b78..8a70dfcb3 100644 --- a/test/type/unit.test.js +++ b/test/type/unit.test.js @@ -1,7 +1,7 @@ // test data type Unit var assert = require('assert'); -var math = require('../../dist/math.js'); +var math = require('../../src/index.js'); var unit1 = math.unit(5000, 'cm');