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
JavaScript
/**
* 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, {