UNPKG

mathjs

Version:

Math.js is an extensive math library for JavaScript and Node.js. It features a flexible expression parser with support for symbolic computation, comes with a large set of built-in functions and constants, and offers an integrated solution to work with dif

1,695 lines (1,421 loc) 1.75 MB
/** * 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 5.7.0 * @date 2019-03-10 * * @license * Copyright (C) 2013-2019 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 * * https://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["math"] = factory(); else root["math"] = 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] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = 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; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); /******/ } /******/ }; /******/ /******/ // define __esModule on exports /******/ __webpack_require__.r = function(exports) { /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); /******/ } /******/ Object.defineProperty(exports, '__esModule', { value: true }); /******/ }; /******/ /******/ // create a fake namespace object /******/ // mode & 1: value is a module id, require it /******/ // mode & 2: merge all properties of value into the ns /******/ // mode & 4: return value when already ns object /******/ // mode & 8|1: behave like require /******/ __webpack_require__.t = function(value, mode) { /******/ if(mode & 1) value = __webpack_require__(value); /******/ if(mode & 8) return value; /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; /******/ var ns = Object.create(null); /******/ __webpack_require__.r(ns); /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); /******/ return ns; /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = 157); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /** * Execute the callback function element wise for each element in array and any * nested array * Returns an array with the results * @param {Array | Matrix} array * @param {Function} callback The callback is called with two parameters: * value1 and value2, which contain the current * element of both arrays. * @param {boolean} [skipZeros] Invoke callback function for non-zero values only. * * @return {Array | Matrix} res */ module.exports = function deepMap(array, callback, skipZeros) { if (array && typeof array.map === 'function') { // TODO: replace array.map with a for loop to improve performance return array.map(function (x) { return deepMap(x, callback, skipZeros); }); } else { return callback(array); } }; /***/ }), /* 1 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; function factory(type, config, load, typed) { /** * Create a Matrix. The function creates a new `math.type.Matrix` object from * an `Array`. A Matrix has utility functions to manipulate the data in the * matrix, like getting the size and getting or setting values in the matrix. * Supported storage formats are 'dense' and 'sparse'. * * Syntax: * * math.matrix() // creates an empty matrix using default storage format (dense). * math.matrix(data) // creates a matrix with initial data using default storage format (dense). * math.matrix('dense') // creates an empty matrix using the given storage format. * math.matrix(data, 'dense') // creates a matrix with initial data using the given storage format. * math.matrix(data, 'sparse') // creates a sparse matrix with initial data. * math.matrix(data, 'sparse', 'number') // creates a sparse matrix with initial data, number data type. * * Examples: * * let m = math.matrix([[1, 2], [3, 4]]) * m.size() // Array [2, 2] * m.resize([3, 2], 5) * m.valueOf() // Array [[1, 2], [3, 4], [5, 5]] * m.get([1, 0]) // number 3 * * See also: * * bignumber, boolean, complex, index, number, string, unit, sparse * * @param {Array | Matrix} [data] A multi dimensional array * @param {string} [format] The Matrix storage format * * @return {Matrix} The created matrix */ var matrix = typed('matrix', { '': function _() { return _create([]); }, 'string': function string(format) { return _create([], format); }, 'string, string': function stringString(format, datatype) { return _create([], format, datatype); }, 'Array': function Array(data) { return _create(data); }, 'Matrix': function Matrix(data) { return _create(data, data.storage()); }, 'Array | Matrix, string': _create, 'Array | Matrix, string, string': _create }); matrix.toTex = { 0: '\\begin{bmatrix}\\end{bmatrix}', 1: "\\left(${args[0]}\\right)", 2: "\\left(${args[0]}\\right)" }; return matrix; /** * Create a new Matrix with given storage format * @param {Array} data * @param {string} [format] * @param {string} [datatype] * @returns {Matrix} Returns a new Matrix * @private */ function _create(data, format, datatype) { // get storage format constructor var M = type.Matrix.storage(format || 'default'); // create instance return new M(data, datatype); } } exports.name = 'matrix'; exports.factory = factory; /***/ }), /* 2 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "size", function() { return size; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "validate", function() { return validate; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "validateIndex", function() { return validateIndex; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "resize", function() { return resize; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "reshape", function() { return reshape; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "squeeze", function() { return squeeze; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "unsqueeze", function() { return unsqueeze; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "flatten", function() { return flatten; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "map", function() { return map; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "forEach", function() { return forEach; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "filter", function() { return filter; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "filterRegExp", function() { return filterRegExp; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "join", function() { return join; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "identify", function() { return identify; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "generalize", function() { return generalize; }); /* harmony import */ var _number__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(3); /* harmony import */ var _number__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_number__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _string__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(9); /* harmony import */ var _string__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_string__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _error_DimensionError__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(8); /* harmony import */ var _error_DimensionError__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_error_DimensionError__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _error_IndexError__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(55); /* harmony import */ var _error_IndexError__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_error_IndexError__WEBPACK_IMPORTED_MODULE_3__); /** * Calculate the size of a multi dimensional array. * This function checks the size of the first entry, it does not validate * whether all dimensions match. (use function `validate` for that) * @param {Array} x * @Return {Number[]} size */ function size(x) { var s = []; while (Array.isArray(x)) { s.push(x.length); x = x[0]; } 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 DimensionError * @private */ function _validate(array, size, dim) { var i; var len = array.length; if (len !== size[dim]) { throw new _error_DimensionError__WEBPACK_IMPORTED_MODULE_2___default.a(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 _error_DimensionError__WEBPACK_IMPORTED_MODULE_2___default.a(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 _error_DimensionError__WEBPACK_IMPORTED_MODULE_2___default.a(size.length + 1, size.length, '>'); } } } } /** * 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 DimensionError */ function validate(array, size) { var isScalar = size.length === 0; if (isScalar) { // scalar if (Array.isArray(array)) { throw new _error_DimensionError__WEBPACK_IMPORTED_MODULE_2___default.a(array.length, 0); } } else { // array _validate(array, size, 0); } } /** * Test whether index is an integer number with index >= 0 and index < length * when length is provided * @param {number} index Zero-based index * @param {number} [length] Length of the array */ function validateIndex(index, length) { if (!_number__WEBPACK_IMPORTED_MODULE_0___default.a.isNumber(index) || !_number__WEBPACK_IMPORTED_MODULE_0___default.a.isInteger(index)) { throw new TypeError('Index must be an integer (value: ' + index + ')'); } if (index < 0 || typeof length === 'number' && index >= length) { throw new _error_IndexError__WEBPACK_IMPORTED_MODULE_3___default.a(index, length); } } /** * Resize a multi dimensional array. The resized array is returned. * @param {Array} array Array to be resized * @param {Array.<number>} size Array with the size of each dimension * @param {*} [defaultValue=0] Value to be filled in in new entries, * zero by default. Specify for example `null`, * to clearly see entries that are not explicitly * set. * @return {Array} array The resized array */ function resize(array, size, defaultValue) { // TODO: add support for scalars, having size=[] ? // check the type of the arguments if (!Array.isArray(array) || !Array.isArray(size)) { throw new TypeError('Array expected'); } if (size.length === 0) { throw new Error('Resizing to scalar is not supported'); } // check whether size contains positive integers size.forEach(function (value) { if (!_number__WEBPACK_IMPORTED_MODULE_0___default.a.isNumber(value) || !_number__WEBPACK_IMPORTED_MODULE_0___default.a.isInteger(value) || value < 0) { throw new TypeError('Invalid size, must contain positive integers ' + '(size: ' + _string__WEBPACK_IMPORTED_MODULE_1___default.a.format(size) + ')'); } }); // recursively resize the array var _defaultValue = defaultValue !== undefined ? defaultValue : 0; _resize(array, size, 0, _defaultValue); return array; } /** * 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, * undefined by default. * @private */ function _resize(array, size, dim, defaultValue) { var i; var elem; var oldLen = array.length; var newLen = size[dim]; var minLen = Math.min(oldLen, newLen); // apply new length array.length = newLen; if (dim < size.length - 1) { // non-last dimension var dimNext = dim + 1; // resize existing child arrays for (i = 0; i < minLen; i++) { // resize child array elem = array[i]; if (!Array.isArray(elem)) { elem = [elem]; // add a dimension array[i] = elem; } _resize(elem, size, dimNext, defaultValue); } // create new child arrays for (i = minLen; i < newLen; i++) { // get child array elem = []; array[i] = elem; // resize new child array _resize(elem, size, dimNext, defaultValue); } } else { // last dimension // remove dimensions of existing values for (i = 0; i < minLen; i++) { while (Array.isArray(array[i])) { array[i] = array[i][0]; } } // fill new elements with the default value for (i = minLen; i < newLen; i++) { array[i] = defaultValue; } } } /** * Re-shape a multi dimensional array to fit the specified dimensions * @param {Array} array Array to be reshaped * @param {Array.<number>} sizes List of sizes for each dimension * @returns {Array} Array whose data has been formatted to fit the * specified dimensions * * @throws {DimensionError} If the product of the new dimension sizes does * not equal that of the old ones */ function reshape(array, sizes) { var flatArray = flatten(array); var newArray; function product(arr) { return arr.reduce(function (prev, curr) { return prev * curr; }); } if (!Array.isArray(array) || !Array.isArray(sizes)) { throw new TypeError('Array expected'); } if (sizes.length === 0) { throw new _error_DimensionError__WEBPACK_IMPORTED_MODULE_2___default.a(0, product(size(array)), '!='); } var totalSize = 1; for (var sizeIndex = 0; sizeIndex < sizes.length; sizeIndex++) { totalSize *= sizes[sizeIndex]; } if (flatArray.length !== totalSize) { throw new _error_DimensionError__WEBPACK_IMPORTED_MODULE_2___default.a(product(sizes), product(size(array)), '!='); } try { newArray = _reshape(flatArray, sizes); } catch (e) { if (e instanceof _error_DimensionError__WEBPACK_IMPORTED_MODULE_2___default.a) { throw new _error_DimensionError__WEBPACK_IMPORTED_MODULE_2___default.a(product(sizes), product(size(array)), '!='); } throw e; } return newArray; } /** * Iteratively re-shape a multi dimensional array to fit the specified dimensions * @param {Array} array Array to be reshaped * @param {Array.<number>} sizes List of sizes for each dimension * @returns {Array} Array whose data has been formatted to fit the * specified dimensions */ function _reshape(array, sizes) { // testing if there are enough elements for the requested shape var tmpArray = array; var tmpArray2; // for each dimensions starting by the last one and ignoring the first one for (var sizeIndex = sizes.length - 1; sizeIndex > 0; sizeIndex--) { var size = sizes[sizeIndex]; tmpArray2 = []; // aggregate the elements of the current tmpArray in elements of the requested size var length = tmpArray.length / size; for (var i = 0; i < length; i++) { tmpArray2.push(tmpArray.slice(i * size, (i + 1) * size)); } // set it as the new tmpArray for the next loop turn or for return tmpArray = tmpArray2; } return tmpArray; } /** * Squeeze a multi dimensional array * @param {Array} array * @param {Array} [arraySize] * @returns {Array} returns the array itself */ function squeeze(array, arraySize) { var s = arraySize || size(array); // squeeze outer dimensions while (Array.isArray(array) && array.length === 1) { array = array[0]; s.shift(); } // find the first dimension to be squeezed var dims = s.length; while (s[dims - 1] === 1) { dims--; } // squeeze inner dimensions if (dims < s.length) { array = _squeeze(array, dims, 0); s.length = dims; } return array; } /** * Recursively squeeze a multi dimensional array * @param {Array} array * @param {number} dims Required number of dimensions * @param {number} dim Current dimension * @returns {Array | *} Returns the squeezed array * @private */ function _squeeze(array, dims, dim) { var i, ii; if (dim < dims) { var next = dim + 1; for (i = 0, ii = array.length; i < ii; i++) { array[i] = _squeeze(array[i], dims, next); } } else { while (Array.isArray(array)) { array = array[0]; } } return array; } /** * Unsqueeze a multi dimensional array: add dimensions when missing * * Paramter `size` will be mutated to match the new, unqueezed matrix size. * * @param {Array} array * @param {number} dims Desired number of dimensions of the array * @param {number} [outer] Number of outer dimensions to be added * @param {Array} [arraySize] Current size of array. * @returns {Array} returns the array itself * @private */ function unsqueeze(array, dims, outer, arraySize) { var s = arraySize || size(array); // unsqueeze outer dimensions if (outer) { for (var i = 0; i < outer; i++) { array = [array]; s.unshift(1); } } // unsqueeze inner dimensions array = _unsqueeze(array, dims, 0); while (s.length < dims) { s.push(1); } return array; } /** * Recursively unsqueeze a multi dimensional array * @param {Array} array * @param {number} dims Required number of dimensions * @param {number} dim Current dimension * @returns {Array | *} Returns the squeezed array * @private */ function _unsqueeze(array, dims, dim) { var i, ii; if (Array.isArray(array)) { var next = dim + 1; for (i = 0, ii = array.length; i < ii; i++) { array[i] = _unsqueeze(array[i], dims, next); } } else { for (var d = dim; d < dims; d++) { array = [array]; } } return array; } /** * Flatten a multi dimensional array, put all elements in a one dimensional * array * @param {Array} array A multi dimensional array * @return {Array} The flattened array (1 dimensional) */ function flatten(array) { if (!Array.isArray(array)) { // if not an array, return as is return array; } var flat = []; array.forEach(function callback(value) { if (Array.isArray(value)) { value.forEach(callback); // traverse through sub-arrays recursively } else { flat.push(value); } }); return flat; } /** * A safe map * @param {Array} array * @param {function} callback */ function map(array, callback) { return Array.prototype.map.call(array, callback); } /** * A safe forEach * @param {Array} array * @param {function} callback */ function forEach(array, callback) { Array.prototype.forEach.call(array, callback); } /** * A safe filter * @param {Array} array * @param {function} callback */ function filter(array, callback) { if (size(array).length !== 1) { throw new Error('Only one dimensional matrices supported'); } return Array.prototype.filter.call(array, callback); } /** * Filter values in a callback given a regular expression * @param {Array} array * @param {RegExp} regexp * @return {Array} Returns the filtered array * @private */ function filterRegExp(array, regexp) { if (size(array).length !== 1) { throw new Error('Only one dimensional matrices supported'); } return Array.prototype.filter.call(array, function (entry) { return regexp.test(entry); }); } /** * A safe join * @param {Array} array * @param {string} separator */ function join(array, separator) { return Array.prototype.join.call(array, separator); } /** * Assign a numeric identifier to every element of a sorted array * @param {Array} a An array * @return {Array} An array of objects containing the original value and its identifier */ function identify(a) { if (!Array.isArray(a)) { throw new TypeError('Array input expected'); } if (a.length === 0) { return a; } var b = []; var count = 0; b[0] = { value: a[0], identifier: 0 }; for (var i = 1; i < a.length; i++) { if (a[i] === a[i - 1]) { count++; } else { count = 0; } b.push({ value: a[i], identifier: count }); } return b; } /** * Remove the numeric identifier from the elements * @param {array} a An array * @return {array} An array of values without identifiers */ function generalize(a) { if (!Array.isArray(a)) { throw new TypeError('Array input expected'); } if (a.length === 0) { return a; } var b = []; for (var i = 0; i < a.length; i++) { b.push(a[i].value); } return b; } /***/ }), /* 3 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var objectUtils = __webpack_require__(5); /** * @typedef {{sign: '+' | '-' | '', coefficients: number[], exponent: number}} SplitValue */ /** * Test whether value is a number * @param {*} value * @return {boolean} isNumber */ exports.isNumber = function (value) { return typeof value === 'number'; }; /** * Check if a number is integer * @param {number | boolean} value * @return {boolean} isInteger */ exports.isInteger = function (value) { if (typeof value === 'boolean') { return true; } return isFinite(value) ? value === Math.round(value) : false; // Note: we use ==, not ===, as we can have Booleans as well }; /** * Calculate the sign of a number * @param {number} x * @returns {*} */ exports.sign = Math.sign || function (x) { if (x > 0) { return 1; } else if (x < 0) { return -1; } else { return 0; } }; /** * Convert a number to a formatted string representation. * * Syntax: * * format(value) * format(value, options) * format(value, precision) * format(value, fn) * * Where: * * {number} value The value to be formatted * {Object} options An object with formatting options. Available options: * {string} notation * Number notation. Choose from: * 'fixed' Always use regular number notation. * For example '123.40' and '14000000' * 'exponential' Always use exponential notation. * For example '1.234e+2' and '1.4e+7' * 'engineering' Always use engineering notation. * For example '123.4e+0' and '14.0e+6' * 'auto' (default) Regular number notation for numbers * having an absolute value between * `lowerExp` and `upperExp` bounds, and * uses exponential notation elsewhere. * Lower bound is included, upper bound * is excluded. * For example '123.4' and '1.4e7'. * {number} precision A number between 0 and 16 to round * the digits of the number. * In case of notations 'exponential', * 'engineering', and 'auto', * `precision` defines the total * number of significant digits returned. * In case of notation 'fixed', * `precision` defines the number of * significant digits after the decimal * point. * `precision` is undefined by default, * not rounding any digits. * {number} lowerExp Exponent determining the lower boundary * for formatting a value with an exponent * when `notation='auto`. * Default value is `-3`. * {number} upperExp Exponent determining the upper boundary * for formatting a value with an exponent * when `notation='auto`. * Default value is `5`. * {Function} fn A custom formatting function. Can be used to override the * built-in notations. Function `fn` is called with `value` as * parameter and must return a string. Is useful for example to * format all values inside a matrix in a particular way. * * Examples: * * format(6.4) // '6.4' * format(1240000) // '1.24e6' * format(1/3) // '0.3333333333333333' * format(1/3, 3) // '0.333' * format(21385, 2) // '21000' * format(12.071, {notation: 'fixed'}) // '12' * format(2.3, {notation: 'fixed', precision: 2}) // '2.30' * format(52.8, {notation: 'exponential'}) // '5.28e+1' * format(12345678, {notation: 'engineering'}) // '12.345678e+6' * * @param {number} value * @param {Object | Function | number} [options] * @return {string} str The formatted value */ exports.format = function (value, options) { if (typeof options === 'function') { // handle format(value, fn) return options(value); } // handle special cases if (value === Infinity) { return 'Infinity'; } else if (value === -Infinity) { return '-Infinity'; } else if (isNaN(value)) { return 'NaN'; } // default values for options var notation = 'auto'; var precision; if (options) { // determine notation from options if (options.notation) { notation = options.notation; } // determine precision from options if (exports.isNumber(options)) { precision = options; } else if (exports.isNumber(options.precision)) { precision = options.precision; } } // handle the various notations switch (notation) { case 'fixed': return exports.toFixed(value, precision); case 'exponential': return exports.toExponential(value, precision); case 'engineering': return exports.toEngineering(value, precision); case 'auto': // TODO: clean up some day. Deprecated since: 2018-01-24 // @deprecated upper and lower are replaced with upperExp and lowerExp since v4.0.0 if (options && options.exponential && (options.exponential.lower !== undefined || options.exponential.upper !== undefined)) { var fixedOptions = objectUtils.map(options, function (x) { return x; }); fixedOptions.exponential = undefined; if (options.exponential.lower !== undefined) { fixedOptions.lowerExp = Math.round(Math.log(options.exponential.lower) / Math.LN10); } if (options.exponential.upper !== undefined) { fixedOptions.upperExp = Math.round(Math.log(options.exponential.upper) / Math.LN10); } console.warn('Deprecation warning: Formatting options exponential.lower and exponential.upper ' + '(minimum and maximum value) ' + 'are replaced with exponential.lowerExp and exponential.upperExp ' + '(minimum and maximum exponent) since version 4.0.0. ' + 'Replace ' + JSON.stringify(options) + ' with ' + JSON.stringify(fixedOptions)); return exports.toPrecision(value, precision, fixedOptions); } return exports.toPrecision(value, precision, options && options) // remove trailing zeros after the decimal point .replace(/((\.\d*?)(0+))($|e)/, function () { var digits = arguments[2]; var e = arguments[4]; return digits !== '.' ? digits + e : e; }); default: throw new Error('Unknown notation "' + notation + '". ' + 'Choose "auto", "exponential", or "fixed".'); } }; /** * Split a number into sign, coefficients, and exponent * @param {number | string} value * @return {SplitValue} * Returns an object containing sign, coefficients, and exponent */ exports.splitNumber = function (value) { // parse the input value var match = String(value).toLowerCase().match(/^0*?(-?)(\d+\.?\d*)(e([+-]?\d+))?$/); if (!match) { throw new SyntaxError('Invalid number ' + value); } var sign = match[1]; var digits = match[2]; var exponent = parseFloat(match[4] || '0'); var dot = digits.indexOf('.'); exponent += dot !== -1 ? dot - 1 : digits.length - 1; var coefficients = digits.replace('.', '') // remove the dot (must be removed before removing leading zeros) .replace(/^0*/, function (zeros) { // remove leading zeros, add their count to the exponent exponent -= zeros.length; return ''; }).replace(/0*$/, '') // remove trailing zeros .split('').map(function (d) { return parseInt(d); }); if (coefficients.length === 0) { coefficients.push(0); exponent++; } return { sign: sign, coefficients: coefficients, exponent: exponent }; }; /** * Format a number in engineering notation. Like '1.23e+6', '2.3e+0', '3.500e-3' * @param {number | string} value * @param {number} [precision] Optional number of significant figures to return. */ exports.toEngineering = function (value, precision) { if (isNaN(value) || !isFinite(value)) { return String(value); } var rounded = exports.roundDigits(exports.splitNumber(value), precision); var e = rounded.exponent; var c = rounded.coefficients; // find nearest lower multiple of 3 for exponent var newExp = e % 3 === 0 ? e : e < 0 ? e - 3 - e % 3 : e - e % 3; if (exports.isNumber(precision)) { // add zeroes to give correct sig figs if (precision > c.length) c = c.concat(zeros(precision - c.length)); } else { // concatenate coefficients with necessary zeros var significandsDiff = e >= 0 ? e : Math.abs(newExp); // add zeros if necessary (for ex: 1e+8) if (c.length - 1 < significandsDiff) c = c.concat(zeros(significandsDiff - (c.length - 1))); } // find difference in exponents var expDiff = Math.abs(e - newExp); var decimalIdx = 1; // push decimal index over by expDiff times while (--expDiff >= 0) { decimalIdx++; } // if all coefficient values are zero after the decimal point and precision is unset, don't add a decimal value. // otherwise concat with the rest of the coefficients var decimals = c.slice(decimalIdx).join(''); var decimalVal = exports.isNumber(precision) && decimals.length || decimals.match(/[1-9]/) ? '.' + decimals : ''; var str = c.slice(0, decimalIdx).join('') + decimalVal + 'e' + (e >= 0 ? '+' : '') + newExp.toString(); return rounded.sign + str; }; /** * Format a number with fixed notation. * @param {number | string} value * @param {number} [precision=undefined] Optional number of decimals after the * decimal point. null by default. */ exports.toFixed = function (value, precision) { if (isNaN(value) || !isFinite(value)) { return String(value); } var splitValue = exports.splitNumber(value); var rounded = typeof precision === 'number' ? exports.roundDigits(splitValue, splitValue.exponent + 1 + precision) : splitValue; var c = rounded.coefficients; var p = rounded.exponent + 1; // exponent may have changed // append zeros if needed var pp = p + (precision || 0); if (c.length < pp) { c = c.concat(zeros(pp - c.length)); } // prepend zeros if needed if (p < 0) { c = zeros(-p + 1).concat(c); p = 1; } // insert a dot if needed if (p < c.length) { c.splice(p, 0, p === 0 ? '0.' : '.'); } return rounded.sign + c.join(''); }; /** * Format a number in exponential notation. Like '1.23e+5', '2.3e+0', '3.500e-3' * @param {number | string} value * @param {number} [precision] Number of digits in formatted output. * If not provided, the maximum available digits * is used. */ exports.toExponential = function (value, precision) { if (isNaN(value) || !isFinite(value)) { return String(value); } // round if needed, else create a clone var split = exports.splitNumber(value); var rounded = precision ? exports.roundDigits(split, precision) : split; var c = rounded.coefficients; var e = rounded.exponent; // append zeros if needed if (c.length < precision) { c = c.concat(zeros(precision - c.length)); } // format as `C.CCCe+EEE` or `C.CCCe-EEE` var first = c.shift(); return rounded.sign + first + (c.length > 0 ? '.' + c.join('') : '') + 'e' + (e >= 0 ? '+' : '') + e; }; /** * Format a number with a certain precision * @param {number | string} value * @param {number} [precision=undefined] Optional number of digits. * @param {{lowerExp: number | undefined, upperExp: number | undefined}} [options] * By default: * lowerExp = -3 (incl) * upper = +5 (excl) * @return {string} */ exports.toPrecision = function (value, precision, options) { if (isNaN(value) || !isFinite(value)) { return String(value); } // determine lower and upper bound for exponential notation. var lowerExp = options && options.lowerExp !== undefined ? options.lowerExp : -3; var upperExp = options && options.upperExp !== undefined ? options.upperExp : 5; var split = exports.splitNumber(value); if (split.exponent < lowerExp || split.exponent >= upperExp) { // exponential notation return exports.toExponential(value, precision); } else { var rounded = precision ? exports.roundDigits(split, precision) : split; var c = rounded.coefficients; var e = rounded.exponent; // append trailing zeros if (c.length < precision) { c = c.concat(zeros(precision - c.length)); } // append trailing zeros // TODO: simplify the next statement c = c.concat(zeros(e - c.length + 1 + (c.length < precision ? precision - c.length : 0))); // prepend zeros c = zeros(-e).concat(c); var dot = e > 0 ? e : 0; if (dot < c.length - 1) { c.splice(dot + 1, 0, '.'); } return rounded.sign + c.join(''); } }; /** * Round the number of digits of a number * * @param {SplitValue} split A value split with .splitNumber(value) * @param {number} precision A positive integer * @return {SplitValue} * Returns an object containing sign, coefficients, and exponent * with rounded digits */ exports.roundDigits = function (split, precision) { // create a clone var rounded = { sign: split.sign, coefficients: split.coefficients, exponent: split.exponent }; var c = rounded.coefficients; // prepend zeros if needed while (precision <= 0) { c.unshift(0); rounded.exponent++; precision++; } if (c.length > precision) { var removed = c.splice(precision, c.length - precision); if (removed[0] >= 5) { var i = precision - 1; c[i]++; while (c[i] === 10) { c.pop(); if (i === 0) { c.unshift(0); rounded.exponent++; i++; } i--; c[i]++; } } } return rounded; }; /** * Create an array filled with zeros. * @param {number} length * @return {Array} */ function zeros(length) { var arr = []; for (var i = 0; i < length; i++) { arr.push(0); } return arr; } /** * Count the number of significant digits of a number. * * For example: * 2.34 returns 3 * 0.0034 returns 2 * 120.5e+30 returns 4 * * @param {number} value * @return {number} digits Number of significant digits */ exports.digits = function (value) { return value.toExponential().replace(/e.*$/, '') // remove exponential notation .replace(/^0\.?0*|\./, '') // remove decimal point and leading zeros .length; }; /** * Minimum number added to one that makes the result different than one */ exports.DBL_EPSILON = Number.EPSILON || 2.2204460492503130808472633361816E-16; /** * Compares two floating point numbers. * @param {number} x First value to compare * @param {number} y Second value to compare * @param {number} [epsilon] The maximum relative difference between x and y * If epsilon is undefined or null, the function will * test whether x and y are exactly equal. * @return {boolean} whether the two numbers are nearly equal */ exports.nearlyEqual = function (x, y, epsilon) { // if epsilon is null or undefined, test whether x and y are exactly equal if (epsilon === null || epsilon === undefined) { return x === y; } if (x === y) { return true; } // NaN if (isNaN(x) || isNaN(y)) { return false; } // at this point x and y should be finite if (isFinite(x) && isFinite(y)) { // check numbers are very close, needed when comparing numbers near zero var diff = Math.abs(x - y); if (diff < exports.DBL_EPSILON) { return true; } else { // use relative error return diff <= Math.max(Math.abs(x), Math.abs(y)) * epsilon; } } // Infinite and Number or negative Infinite and positive Infinite cases return false; }; /***/ }), /* 4 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var escapeLatex = __webpack_require__(176); exports.symbols = { // GREEK LETTERS Alpha: 'A', alpha: '\\alpha', Beta: 'B', beta: '\\beta', Gamma: '\\Gamma', gamma: '\\gamma', Delta: '\\Delta', delta: '\\delta', Epsilon: 'E', epsilon: '\\epsilon', varepsilon: '\\varepsilon', Zeta: 'Z', zeta: '\\zeta', Eta: 'H', eta: '\\eta', Theta: '\\Theta', theta: '\\theta', vartheta: '\\vartheta', Iota: 'I', iota: '\\iota', Kappa: 'K', kappa: '\\kappa', varkappa: '\\varkappa', Lambda: '\\Lambda', lambda: '\\lambda', Mu: 'M', mu: '\\mu', Nu: 'N', nu: '\\nu', Xi: '\\Xi', xi: '\\xi', Omicron: 'O', omicron: 'o', Pi: '\\Pi', pi: '\\pi', varpi: '\\varpi', Rho: 'P', rho: '\\rho', varrho: '\\varrho', Sigma: '\\Sigma', sigma: '\\sigma', varsigma: '\\varsigma', Tau: 'T', tau: '\\tau', Upsilon: "\\Upsilon", upsilon: "\\upsilon", Phi: '\\Phi', phi: '\\phi', varphi: '\\varphi', Chi: 'X', chi: '\\chi', Psi: '\\Psi', psi: '\\psi', Omega: '\\Omega', omega: '\\omega', // logic 'true': '\\mathrm{True}', 'false': '\\mathrm{False}', // other i: 'i', // TODO use \i ?? inf: '\\infty', Inf: '\\infty', infinity: '\\infty', Infinity: '\\infty', oo: '\\infty', lim: '\\lim', 'undefined': '\\mathbf{?}' }; exports.operators = { 'transpose': '^\\top', 'ctranspose': '^H', 'factorial': '!', 'pow': '^', 'dotPow': '.^\\wedge', // TODO find ideal solution 'unaryPlus': '+', 'unaryMinus': '-', 'bitNot': '\\~', // TODO find ideal solution 'not': '\\neg', 'multiply': '\\cdot', 'divide': '\\frac', // TODO how to handle that properly? 'dotMultiply': '.\\cdot', // TODO find ideal solution 'dotDivide': '.:', // TODO find ideal solution 'mod': '\\mod', 'add': '+', 'subtract': '-', 'to': '\\rightarrow', 'leftShift': '<<', 'rightArithShift': '>>', 'rightLogShift': '>>>', 'equal': '=', 'unequal': '\\neq', 'smaller': '<', 'larger': '>', 'smallerEq': '\\leq', 'largerEq': '\\geq', 'bitAnd': '\\&', 'bitXor': "\\underline{|}", 'bitOr': '|', 'and': '\\wedge', 'xor': '\\veebar', 'or': '\\vee' }; exports.defaultTemplate = "\\mathrm{${name}}\\left(${args}\\right)"; var units = { deg: '^\\circ' }; exports.escape = function (string) { return escapeLatex(string, { 'preserveFormatting': true }); }; // @param {string} name // @param {boolean} isUnit exports.toSymbol = function (name, isUnit) { isUnit = typeof isUnit === 'undefined' ? false : isUnit; if (isUnit) { if (units.hasOwnProperty(name)) { return units[name]; } return '\\mathrm{' + exports.escape(name) + '}'; } if (exports.symbols.hasOwnProperty(name)) { return exports.symbols[name]; } return exports.escape(name); }; /***/ }), /* 5 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } var isBigNumber = __webpack_require__(80); /** * 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 Date) return new Date(x.valueOf()); if (isBigNumber(x)) return x; // bignumbers are immutable if (x instanceof RegExp) throw new TypeError('Cannot clone ' + x); // TODO: clone a RegExp // object return exports.map(x, clone); }; /** * Apply map to all properties of an object * @param {Object} object * @param {function} callback * @return {Object} Returns a copy of the object with mapped properties */ exports.map = function (object, callback) { var clone = {}; for (var key in object) { if (exports.hasOwnProperty(object, key)) { clone[key] = callback(object[key]); } } return clone; }; /** * Extend object a with the properties of object b * @param {Object} a * @param {Object} b * @return {Object} a */ exports.extend = function (a, b) { for (var prop in b) { if (exports.hasOwnProperty(b, 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 (exports.hasOwnProperty(b, 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 a === b; } }; /** * Test whether the current JavaScript engine supports Object.defineProperty * @returns {boolean} returns true if supported */ exports.canDefineProperty = function () { // test needed for broken IE8 implementation try { if (Object.defineProperty) { Object.defineProperty({}, 'x', { get: function get() {} }); return true; } } catch (e) {} return false; }; /** * Attach a lazy loading property to a constant. * The given function `fn` is called once when the property is first requested. * On older browsers (<IE8), the function will fall back to direct evaluation * of the properties value. * @param {Object} object Object where to add the property * @param {string} prop Property name * @param {Function} fn Function returning the property value. Called * without arguments. */ exports.lazy = function (object, prop, fn) { if (exports.canDefineProperty()) { var _uninitialized = true; var _value; Object.defineProperty(object, prop, {