UNPKG

mathjs

Version:

Math.js is an extensive math library for JavaScript and Node.js. It features a flexible expression parser and offers an integrated solution to work with numbers, big numbers, complex numbers, units, and matrices.

1,855 lines (1,627 loc) 693 kB
/** * 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.20.0 * @date 2014-04-16 * * @license * Copyright (C) 2013-2014 Jos de Jong <wjosdejong@gmail.com> * * 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 webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if(typeof define === 'function' && define.amd) define(factory); else if(typeof exports === 'object') exports["mathjs"] = factory(); else root["mathjs"] = factory(); })(this, function() { return /******/ (function(modules) { // webpackBootstrap /******/ /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) /******/ return installedModules[moduleId].exports; /******/ /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ exports: {}, /******/ id: moduleId, /******/ loaded: false /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.loaded = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(0); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ function(module, exports, __webpack_require__) { module.exports = __webpack_require__(1); /***/ }, /* 1 */ /***/ function(module, exports, __webpack_require__) { var object = __webpack_require__(3); /** * math.js factory function. * * Usage: * * var math = mathjs(); * var math = mathjs(config); * * @param {Object} [config] Available configuration options: * {String} matrix * A string 'matrix' (default) or 'array'. * {String} number * A string 'number' (default) or 'bignumber' * {Number} precision * The number of significant digits for BigNumbers. * Not applicable for Numbers. */ function mathjs (config) { // simple test for ES5 support if (typeof Object.create !== 'function') { throw new Error('ES5 not supported by this JavaScript engine. ' + 'Please load the es5-shim and es5-sham library for compatibility.'); } // create new namespace var math = {}; // create configuration options. These are private var _config = { // type of default matrix output. Choose 'matrix' (default) or 'array' matrix: 'matrix', // type of default number output. Choose 'number' (default) or 'bignumber' number: 'number', // number of significant digits in BigNumbers precision: 20, // minimum relative difference between two compared values, // used by all comparison functions epsilon: 1e-14 }; /** * Set configuration options for math.js, and get current options * @param {Object} [options] Available options: * {String} matrix * A string 'matrix' (default) or 'array'. * {String} number * A string 'number' (default) or 'bignumber' * {Number} precision * The number of significant digits for BigNumbers. * Not applicable for Numbers. * @return {Object} Returns the current configuration */ math.config = function config (options) { if (options) { // merge options object.deepExtend(_config, options); if (options.precision) { math.type.BigNumber.config({ precision: options.precision }); } // TODO: remove deprecated setting some day (deprecated since version 0.17.0) if (options.number && options.number.defaultType) { throw new Error('setting `number.defaultType` is deprecated. Use `number` instead.') } // TODO: remove deprecated setting some day (deprecated since version 0.17.0) if (options.number && options.number.precision) { throw new Error('setting `number.precision` is deprecated. Use `precision` instead.') } // TODO: remove deprecated setting some day (deprecated since version 0.17.0) if (options.matrix && options.matrix.defaultType) { throw new Error('setting `matrix.defaultType` is deprecated. Use `matrix` instead.') } // TODO: remove deprecated setting some day (deprecated since version 0.15.0) if (options.matrix && options.matrix['default']) { throw new Error('setting `matrix.default` is deprecated. Use `matrix` instead.') } // TODO: remove deprecated setting some day (deprecated since version 0.20.0) if (options.decimals) { throw new Error('setting `decimals` is deprecated. Use `precision` instead.') } } // return a clone of the settings return object.clone(_config); }; // create a new BigNumber factory for this instance of math.js var BigNumber = __webpack_require__(112).constructor(); // extend BigNumber with a function clone if (typeof BigNumber.prototype.clone !== 'function') { /** * Clone a bignumber * @return {BigNumber} clone */ BigNumber.prototype.clone = function clone () { return new BigNumber(this); }; } // extend BigNumber with a function convert if (typeof BigNumber.convert !== 'function') { /** * Try to convert a Number in to a BigNumber. * If the number has 15 or mor significant digits, the Number cannot be * converted to BigNumber and will return the original number. * @param {Number} number * @return {BigNumber | Number} bignumber */ BigNumber.convert = function convert(number) { if (digits(number) > 15) { return number; } else { return new BigNumber(number); } }; } else { throw new Error('Cannot add function convert to BigNumber: function already exists'); } // errors math.error = __webpack_require__(4); // types (Matrix, Complex, Unit, ...) math.type = {}; math.type.Complex = __webpack_require__(5); math.type.Range = __webpack_require__(6); math.type.Index = __webpack_require__(7); math.type.Matrix = __webpack_require__(8); math.type.Unit = __webpack_require__(9); math.type.Help = __webpack_require__(10); math.type.BigNumber = BigNumber; math.collection = __webpack_require__(11); // expression (parse, Parser, nodes, docs) math.expression = {}; math.expression.node = __webpack_require__(14); math.expression.parse = __webpack_require__(12); math.expression.Scope = function () { throw new Error('Scope is deprecated. Use a regular Object instead'); }; math.expression.Parser = __webpack_require__(13); math.expression.docs = __webpack_require__(15); // expression parser __webpack_require__(17)(math, _config); __webpack_require__(18)(math, _config); __webpack_require__(19)(math, _config); __webpack_require__(20)(math, _config); // functions - arithmetic __webpack_require__(21)(math, _config); __webpack_require__(22)(math, _config); __webpack_require__(23)(math, _config); __webpack_require__(24)(math, _config); __webpack_require__(25)(math, _config); __webpack_require__(26)(math, _config); __webpack_require__(27)(math, _config); __webpack_require__(28)(math, _config); __webpack_require__(29)(math, _config); __webpack_require__(30)(math, _config); __webpack_require__(31)(math, _config); __webpack_require__(32)(math, _config); __webpack_require__(33)(math, _config); __webpack_require__(34)(math, _config); __webpack_require__(35)(math, _config); __webpack_require__(36)(math, _config); __webpack_require__(37)(math, _config); __webpack_require__(38)(math, _config); __webpack_require__(39)(math, _config); __webpack_require__(40)(math, _config); __webpack_require__(41)(math, _config); __webpack_require__(42)(math, _config); __webpack_require__(43)(math, _config); __webpack_require__(44)(math, _config); __webpack_require__(45)(math, _config); __webpack_require__(46)(math, _config); __webpack_require__(47)(math, _config); __webpack_require__(48)(math, _config); __webpack_require__(49)(math, _config); __webpack_require__(50)(math, _config); __webpack_require__(51)(math, _config); __webpack_require__(52)(math, _config); __webpack_require__(53)(math, _config); // functions - complex __webpack_require__(54)(math, _config); __webpack_require__(55)(math, _config); __webpack_require__(56)(math, _config); __webpack_require__(57)(math, _config); // functions - construction __webpack_require__(58)(math, _config); __webpack_require__(59)(math, _config); __webpack_require__(60)(math, _config); __webpack_require__(61)(math, _config); __webpack_require__(62)(math, _config); __webpack_require__(63)(math, _config); __webpack_require__(64)(math, _config); __webpack_require__(65)(math, _config); __webpack_require__(66)(math, _config); __webpack_require__(67)(math, _config); // functions - matrix __webpack_require__(68)(math, _config); __webpack_require__(69)(math, _config); __webpack_require__(70)(math, _config); __webpack_require__(71)(math, _config); __webpack_require__(72)(math, _config); __webpack_require__(73)(math, _config); __webpack_require__(74)(math, _config); __webpack_require__(75)(math, _config); __webpack_require__(76)(math, _config); __webpack_require__(77)(math, _config); __webpack_require__(78)(math, _config); __webpack_require__(79)(math, _config); __webpack_require__(80)(math, _config); // functions - probability __webpack_require__(81)(math, _config); __webpack_require__(82)(math, _config); __webpack_require__(83)(math, _config); __webpack_require__(84)(math, _config); // functions - statistics __webpack_require__(85)(math, _config); __webpack_require__(86)(math, _config); __webpack_require__(87)(math, _config); __webpack_require__(88)(math, _config); __webpack_require__(89)(math, _config); __webpack_require__(90)(math, _config); __webpack_require__(91)(math, _config); __webpack_require__(92)(math, _config); // functions - trigonometry __webpack_require__(93)(math, _config); __webpack_require__(94)(math, _config); __webpack_require__(95)(math, _config); __webpack_require__(96)(math, _config); __webpack_require__(97)(math, _config); __webpack_require__(98)(math, _config); __webpack_require__(99)(math, _config); __webpack_require__(100)(math, _config); __webpack_require__(101)(math, _config); __webpack_require__(102)(math, _config); // functions - units __webpack_require__(103)(math, _config); // functions - utils __webpack_require__(104)(math, _config); __webpack_require__(105)(math, _config); __webpack_require__(106)(math, _config); __webpack_require__(107)(math, _config); __webpack_require__(108)(math, _config); __webpack_require__(109)(math, _config); __webpack_require__(110)(math, _config); __webpack_require__(111)(math, _config); // constants __webpack_require__(2)(math, _config); // selector (we initialize after all functions are loaded) math.chaining = {}; math.chaining.Selector = __webpack_require__(16)(math, _config); // apply provided configuration options math.config(config); // return the new instance return math; } // return the mathjs factory module.exports = mathjs; /***/ }, /* 2 */ /***/ function(module, exports, __webpack_require__) { module.exports = function (math) { var Complex = __webpack_require__(5); 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; }; /***/ }, /* 3 */ /***/ function(module, exports, __webpack_require__) { /** * Clone an object * * clone(x) * * Can clone any primitive type, array, and object. * If x has a function clone, this function will be invoked to clone the object. * * @param {*} x * @return {*} clone */ exports.clone = function clone(x) { var type = typeof x; // immutable primitive types if (type === 'number' || type === 'string' || type === 'boolean' || x === null || x === undefined) { return x; } // use clone function of the object when available if (typeof x.clone === 'function') { return x.clone(); } // array if (Array.isArray(x)) { return x.map(function (value) { return clone(value); }); } if (x instanceof Number) return new Number(x.valueOf()); if (x instanceof String) return new String(x.valueOf()); if (x instanceof Boolean) return new Boolean(x.valueOf()); if (x instanceof Date) return new Date(x.valueOf()); if (x instanceof RegExp) throw new TypeError('Cannot clone ' + x); // TODO: clone a RegExp // object var m = {}; for (var key in x) { if (x.hasOwnProperty(key)) { m[key] = clone(x[key]); } } return m; }; /** * 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) { // TODO: add support for Arrays to deepExtend if (Array.isArray(b)) { throw new TypeError('Arrays are not supported by deepExtend'); } 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 if (Array.isArray(b[prop])) { throw new TypeError('Arrays are not supported by deepExtend'); } 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; } if (a.length != b.length) { 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) { //noinspection JSUnfilteredForInLoop if (!exports.deepEqual(a[prop], b[prop])) { return false; } } for (prop in b) { //noinspection JSUnfilteredForInLoop if (!exports.deepEqual(a[prop], b[prop])) { return false; } } return true; } else { return (typeof a === typeof b) && (a == b); } }; /***/ }, /* 4 */ /***/ function(module, exports, __webpack_require__) { exports.ArgumentsError = __webpack_require__(113); exports.DimensionError = __webpack_require__(114); exports.IndexError = __webpack_require__(115); exports.UnsupportedTypeError = __webpack_require__(116); // TODO: implement an InvalidValueError? /***/ }, /* 5 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(117), Unit = __webpack_require__(9), number = util.number, isNumber = util.number.isNumber, isUnit = Unit.isUnit, isString = util.string.isString; /** * @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('Constructor must be called with the new operator'); } switch (arguments.length) { case 0: this.re = 0; this.im = 0; break; case 1: var arg = arguments[0]; if (typeof arg === 'object') { if('re' in arg && 'im' in arg) { var construct = new Complex(arg.re, arg.im); // pass on input validation this.re = construct.re; this.im = construct.im; break; } else if ('r' in arg && 'phi' in arg) { var construct = Complex.fromPolar(arg.r, arg.phi); this.re = construct.re; this.im = construct.im; break; } } throw new SyntaxError('Object with the re and im or r and phi properties expected.'); case 2: if (!isNumber(re) || !isNumber(im)) { throw new TypeError('Two numbers expected in Complex constructor'); } this.re = re; this.im = im; break; default: throw new SyntaxError('One, two or three arguments expected in Complex constructor'); } } /** * Test whether value is a Complex value * @param {*} value * @return {Boolean} isComplex */ 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 exponential 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; } /** * 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 complex number from polar coordinates * * Usage: * * Complex.fromPolar(r: Number, phi: Number) : Complex * Complex.fromPolar({r: Number, phi: Number}) : Complex * * @param {*} args... * @return {Complex} */ Complex.fromPolar = function fromPolar(args) { switch (arguments.length) { case 1: var arg = arguments[0]; if(typeof arg === 'object') { return Complex.fromPolar(arg.r, arg.phi); } throw new TypeError('Input has to be an object with r and phi keys.'); case 2: var r = arguments[0], phi = arguments[1]; if(isNumber(r)) { if (isUnit(phi) && phi.hasBase(Unit.BASE_UNITS.ANGLE)) { // convert unit to a number in radians phi = phi.toNumber('rad'); } if(isNumber(phi)) { return new Complex(r * Math.cos(phi), r * Math.sin(phi)); } throw new TypeError('Phi is not a number nor an angle unit.'); } else { throw new TypeError('Radius r is not a number.'); } default: throw new SyntaxError('Wrong number of arguments in function fromPolar'); } }; /* * Return the value of the complex number in polar notation * The angle phi will be set in the interval of [-pi, pi]. * @return {{r: number, phi: number}} Returns and object with properties r and phi. */ Complex.prototype.toPolar = function() { return { r: Math.sqrt(this.re * this.re + this.im * this.im), phi: Math.atan2(this.im, this.re) }; }; /** * Create a copy of the complex value * @return {Complex} clone */ Complex.prototype.clone = function clone () { return new Complex(this.re, this.im); }; /** * Test whether this complex number equals an other complex value. * Two complex numbers are equal when both their real and imaginary parts * are equal. * @param {Complex} other * @return {boolean} isEqual */ Complex.prototype.equals = function equals (other) { return (this.re === other.re) && (this.im === other.im); }; /** * Get a string representation of the complex number, * with optional formatting options. * @param {Object | Number | Function} [options] Formatting options. See * lib/util/number:format for a * description of the available * options. * @return {String} str */ Complex.prototype.format = function format (options) { var str = '', strRe = number.format(this.re, options), strIm = number.format(this.im, options); 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 + ' - ' + strIm.substring(1) + 'i'; } } } return str; }; /** * Get a string representation of the complex number. * @return {String} str */ Complex.prototype.toString = function toString () { return this.format(); }; // exports module.exports = Complex; /***/ }, /* 6 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(117), number = util.number, string = util.string, array = util.array; /** * @constructor Range * Create a range. A range has a start, step, and end, and contains functions * to iterate over the range. * * A range can be constructed as: * var range = new Range(start, end); * var range = new Range(start, end, step); * * 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, 6); // 2:1:5 * c.toArray(); // [2, 3, 4, 5] * var d = new Range(2, -3, -1); // 2:-1:-2 * d.toArray(); // [2, 1, 0, -1, -2] * * @param {Number} start included lower bound * @param {Number} end excluded upper bound * @param {Number} [step] step size, default value is 1 */ function Range(start, end, step) { if (!(this instanceof Range)) { throw new SyntaxError('Constructor must be called with the new operator'); } if (start != null && !number.isNumber(start)) { throw new TypeError('Parameter start must be a number'); } if (end != null && !number.isNumber(end)) { throw new TypeError('Parameter end must be a number'); } if (step != null && !number.isNumber(step)) { throw new TypeError('Parameter step must be a number'); } this.start = (start != null) ? parseFloat(start) : 0; this.end = (end != null) ? parseFloat(end) : 0; this.step = (step != null) ? parseFloat(step) : 1; } /** * 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:11'. * @param {String} str * @return {Range | null} range */ Range.parse = function parse (str) { if (!string.isString(str)) { return null; } var args = str.split(':'); var nums = args.map(function (arg) { return parseFloat(arg); }); var invalid = nums.some(function (num) { return isNaN(num); }); if(invalid) { return null; } switch (nums.length) { case 2: return new Range(nums[0], nums[1]); case 3: return new Range(nums[0], nums[2], nums[1]); default: return null; } }; /** * Create a clone of the range * @return {Range} clone */ Range.prototype.clone = function clone() { return new Range(this.start, this.end, this.step); }; /** * 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 an array containing one number, the number of elements in the range. * @returns {Number[]} size */ Range.prototype.size = function size() { var len = 0, start = this.start, step = this.step, end = this.end, diff = end - start; if (number.sign(step) == number.sign(diff)) { len = Math.ceil((diff) / step); } else if (diff == 0) { len = 0; } if (isNaN(len)) { len = 0; } return [len]; }; /** * Calculate the minimum value in the range * @return {Number | undefined} min */ Range.prototype.min = function min () { var size = this.size()[0]; if (size > 0) { if (this.step > 0) { // positive step return this.start; } else { // negative step return this.start + (size - 1) * this.step; } } else { return undefined; } }; /** * Calculate the maximum value in the range * @return {Number | undefined} max */ Range.prototype.max = function max () { var size = this.size()[0]; if (size > 0) { if (this.step > 0) { // positive step return this.start + (size - 1) * this.step; } else { // negative step return this.start; } } else { return undefined; } }; /** * 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 forEach(callback) { var x = this.start; var step = this.step; var end = 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 map(callback) { var array = []; this.forEach(function (value, index, obj) { array[index] = callback(value, index, obj); }); return array; }; /** * Create an Array with a copy of the Ranges data * @returns {Array} array */ Range.prototype.toArray = function toArray() { var array = []; this.forEach(function (value, index) { array[index] = value; }); return array; }; /** * Get the primitive value of the Range, a one dimensional array * @returns {Array} array */ Range.prototype.valueOf = function valueOf() { // TODO: implement a caching mechanism for range.valueOf() return this.toArray(); }; /** * Get a string representation of the range, with optional formatting options. * Output is formatted as 'start:step:end', for example '2:6' or '0:0.2:11' * @param {Object | Number | Function} [options] Formatting options. See * lib/util/number:format for a * description of the available * options. * @returns {String} str */ Range.prototype.format = function format(options) { var str = number.format(this.start, options); if (this.step != 1) { str += ':' + number.format(this.step, options); } str += ':' + number.format(this.end, options); return str; }; /** * Get a string representation of the range. * @returns {String} */ Range.prototype.toString = function toString() { return this.format(); }; // exports module.exports = Range; /***/ }, /* 7 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(117), Range = __webpack_require__(6), number = util.number, isNumber = number.isNumber, isInteger = number.isInteger, isArray = Array.isArray, validateIndex = util.array.validateIndex; /** * @Constructor Index * Create an index. An Index can store ranges having start, step, and end * for multiple dimensions. * Matrix.get, Matrix.set, and math.subset accept an Index as input. * * Usage: * var index = new Index(range1, range2, ...); * * Where each range can be any of: * An array [start, end] * An array [start, end, step] * A number * An instance of Range * * The parameters start, end, and step must be integer numbers. * * @param {...*} ranges */ function Index(ranges) { if (!(this instanceof Index)) { throw new SyntaxError('Constructor must be called with the new operator'); } this._ranges = []; for (var i = 0, ii = arguments.length; i < ii; i++) { var arg = arguments[i]; if (arg instanceof Range) { this._ranges.push(arg); } else { if (isArray(arg)) { this._ranges.push(_createRange(arg)); } else if (isNumber(arg)) { this._ranges.push(_createRange([arg, arg + 1])); } // TODO: implement support for wildcard '*' else { throw new TypeError('Ranges must be an Array, Number, or Range'); } } } } /** * Parse an argument into a range and validate the range * @param {Array} arg An array with [start: Number, end: Number] and * optional a third element step:Number * @return {Range} range * @private */ function _createRange(arg) { // TODO: make function _createRange simpler/faster // test whether all arguments are integers var num = arg.length; for (var i = 0; i < num; i++) { if (!isNumber(arg[i]) || !isInteger(arg[i])) { throw new TypeError('Index parameters must be integer numbers'); } } switch (arg.length) { case 2: return new Range(arg[0], arg[1]); // start, end case 3: return new Range(arg[0], arg[1], arg[2]); // start, end, step default: // TODO: improve error message throw new SyntaxError('Wrong number of arguments in Index (2 or 3 expected)'); } } /** * Create a clone of the index * @return {Index} clone */ Index.prototype.clone = function clone () { var index = new Index(); index._ranges = util.object.clone(this._ranges); return index; }; /** * Test whether an object is an Index * @param {*} object * @return {Boolean} isIndex */ Index.isIndex = function isIndex(object) { return (object instanceof Index); }; /** * Create an index from an array with ranges/numbers * @param {Array.<Array | Number>} ranges * @return {Index} index * @private */ Index.create = function create(ranges) { var index = new Index(); Index.apply(index, ranges); return index; }; /** * Retrieve the size of the index, the number of elements for each dimension. * @returns {Number[]} size */ Index.prototype.size = function size () { var size = []; for (var i = 0, ii = this._ranges.length; i < ii; i++) { var range = this._ranges[i]; size[i] = range.size()[0]; } return size; }; /** * Get the maximum value for each of the indexes ranges. * @returns {Number[]} max */ Index.prototype.max = function max () { var values = []; for (var i = 0, ii = this._ranges.length; i < ii; i++) { var range = this._ranges[i]; values[i] = range.max(); } return values; }; /** * Get the minimum value for each of the indexes ranges. * @returns {Number[]} min */ Index.prototype.min = function min () { var values = []; for (var i = 0, ii = this._ranges.length; i < ii; i++) { var range = this._ranges[i]; values[i] = range.min(); } return values; }; /** * Loop over each of the ranges of the index * @param {function} callback Called for each range with a Range as first * argument, the dimension as second, and the * index object as third. */ Index.prototype.forEach = function forEach(callback) { for (var i = 0, ii = this._ranges.length; i < ii; i++) { callback(this._ranges[i], i, this); } }; /** * Retrieve the range for a given dimension number from the index * @param {Number} dim Number of the dimension * @returns {Range | null} range */ Index.prototype.range = function range (dim) { return this._ranges[dim] || null; }; /** * Test whether this index contains only a single value * @return {boolean} isScalar */ Index.prototype.isScalar = function isScalar () { var size = this.size(); for (var i = 0, ii = size.length; i < ii; i++) { if (size[i] !== 1) { return false; } } return true; }; /** * Expand the Index into an array. * For example new Index([0,3], [2,7]) returns [[0,1,2], [2,3,4,5,6]] * @returns {Array} array */ Index.prototype.toArray = function toArray() { var array = []; for (var i = 0, ii = this._ranges.length; i < ii; i++) { var range = this._ranges[i], row = [], x = range.start, end = range.end, step = range.step; if (step > 0) { while (x < end) { row.push(x); x += step; } } else if (step < 0) { while (x > end) { row.push(x); x += step; } } array.push(row); } return array; }; /** * Get the primitive value of the Index, a two dimensional array. * Equivalent to Index.toArray(). * @returns {Array} array */ Index.prototype.valueOf = Index.prototype.toArray; /** * Get the string representation of the index, for example '[2:6]' or '[0:2:10, 4:7]' * @returns {String} str */ Index.prototype.toString = function () { var strings = []; for (var i = 0, ii = this._ranges.length; i < ii; i++) { var range = this._ranges[i]; var str = number.format(range.start); if (range.step != 1) { str += ':' + number.format(range.step); } str += ':' + number.format(range.end); strings.push(str); } return '[' + strings.join(', ') + ']'; }; // exports module.exports = Index; /***/ }, /* 8 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(117), DimensionError = __webpack_require__(114), Index = __webpack_require__(7), number = util.number, string = util.string, array = util.array, object = util.object, isArray = Array.isArray, validateIndex = array.validateIndex; /** * @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 function 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.subset([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('Constructor must be called with the new operator'); } if (data instanceof Matrix) { // clone data from a Matrix this._data = data.clone()._data; } else if (isArray(data)) { // use array // replace nested Matrices with Arrays this._data = preprocess(data); } else if (data != null) { // unsupported type throw new TypeError('Unsupported type of data (' + util.types.type(data) + ')'); } else { // nothing provided this._data = []; } // verify the size of the array this._size = array.size(this._data); } /** * Test whether an object is a Matrix * @param {*} object * @return {Boolean} isMatrix */ Matrix.isMatrix = function isMatrix(object) { return (object instanceof Matrix); }; /** * Get a subset of the matrix, or replace a subset of the matrix. * * Usage: * var subset = matrix.subset(index) // retrieve subset * var value = matrix.subset(index, replacement) // replace subset * * @param {Index} index * @param {Array | Matrix | *} [replacement] * @param {*} [defaultValue] Default value, filled in on new entries when * the matrix is resized. If not provided, * new matrix elements will be left undefined. */ Matrix.prototype.subset = function subset(index, replacement, defaultValue) { switch (arguments.length) { case 1: return _get(this, index); // intentional fall through case 2: case 3: return _set(this, index, replacement, defaultValue); default: throw new SyntaxError('Wrong number of arguments'); } }; /** * Get a single element from the matrix. * @param {Number[]} index Zero-based index * @return {*} value */ Matrix.prototype.get = function get(index) { if (!isArray(index)) { throw new TypeError('Array expected'); } if (index.length != this._size.length) { throw new DimensionError(index.length, this._size.length); } var data = this._data; for (var i = 0, ii = index.length; i < ii; i++) { var index_i = index[i]; validateIndex(index_i, data.length); data = data[index_i]; } return object.clone(data); }; /** * Replace a single element in the matrix. * @param {Number[]} index Zero-based index * @param {*} value * @param {*} [defaultValue] Default value, filled in on new entries when * the matrix is resized. If not provided, * new matrix elements will be left undefined. * @return {Matrix} self */ Matrix.prototype.set = function set (index, value, defaultValue) { var i, ii; // validate input type and dimensions if (!isArray(index)) { throw new Error('Array expected'); } if (index.length < this._size.length) { throw new DimensionError(index.length, this._size.length, '<'); } // enlarge matrix when needed var size = index.map(function (i) { return i + 1; }); _fit(this, size, defaultValue); // traverse over the dimensions var data = this._data; for (i = 0, ii = index.length - 1; i < ii; i++) { var index_i = index[i]; validateIndex(index_i, data.length); data = data[index_i]; } // set new value index_i = index[index.length - 1]; validateIndex(index_i, data.length); data[index_i] = value; return this; }; /** * Get a submatrix of this matrix * @param {Matrix} matrix * @param {Index} index Zero-based index * @private */ function _get (matrix, index) { if (!(index instanceof Index)) { throw new TypeError('Invalid index'); } var isScalar = index.isScalar(); if (isScalar) { // return a scalar return matrix.get(index.min()); } else { // validate dimensions var size = index.size(); if (size.length != matrix._size.length) { throw new DimensionError(size.length, matrix._size.length); } // retrieve submatrix var submatrix = new Matrix(_getSubmatrix(matrix._data, index, size.length, 0)); // TODO: more efficient when creating an empty matrix and setting _data and _size manually // squeeze matrix output while (isArray(submatrix._data) && submatrix._data.length == 1) { submatrix._data = submatrix._data[0]; submatrix._size.shift(); } return submatrix; } } /** * Recursively get a submatrix of a multi dimensional matrix. * Index is not checked for correct number of dimensions. * @param {Array} data * @param {Index} index * @param {number} dims Total number of dimensions * @param {number} dim Current dimension * @return {Array} submatrix * @private */ function _getSubmatrix (data, index, dims, dim) { var last = (dim == dims - 1); var range = index.range(dim); if (last) { return range.map(function (i) { validateIndex(i, data.length); return data[i]; }); } else { return range.map(function (i) { validateIndex(i, data.length); var child = data[i]; return _getSubmatrix(child, index, dims, dim + 1); }); } } /** * Replace a submatrix in this matrix * Indexes are zero-based. * @param {Matrix} matrix * @param {Index} index * @param {Matrix | Array | *} submatrix * @param {*} [defaultValue] Default value, filled in on new entries when * the matrix is resized. If not provided, * new matrix elements will be left undefined. * @return {Matrix} matrix * @private */ function _set (matrix, index, submatrix, defaultValue) { if (!(index instanceof Index)) { throw new TypeError('Invalid index'); } // get index size and check whether the index contains a single value var iSize = index.size(), isScalar = index.isScalar(); // calculate the size of the submatrix, and convert it into an Array if needed var sSize; if (submatrix instanceof Matrix) { sSize = submatrix.size(); submatrix = submatrix.valueOf(); } else { sSize = array.size(submatrix); } if (isScalar) { // set a scalar // check whether submatrix is a scalar if (sSize.length != 0) { throw new TypeError('Scalar expected'); } matrix.set(index.min(), submatrix, defaultValue); } else { // set a submatrix // validate dimensions if (iSize.length < matrix._size.length) { throw new DimensionError(iSize.length, matrix._size.length, '<'); } // unsqueeze the submatrix when needed for (var i = 0, ii = iSize.length - sSize.length; i < ii; i++) { submatrix = [submatrix]; sSize.unshift(1); } // check whether the size of the submatrix matches the index size if (!object.deepEqual(iSize, sSize)) { throw new DimensionError(iSize, sSize); } // enlarge matrix when needed var size = index.max().map(function (i) { return i + 1; }); _fit(matrix, size, defaultValue); // insert the sub matrix var dims = iSiz